# Part of Odoo. See LICENSE file for full copyright and licensing details.

from werkzeug.urls import url_encode

from odoo import fields, models, api, _
from odoo.exceptions import UserError, ValidationError


class CouponShare(models.TransientModel):
    _name = 'coupon.share'
    _description = 'Create links that apply a coupon and redirect to a specific page'

    def _get_default_website_id(self):
        program_website_id = self.env['loyalty.program'].browse(self.env.context.get('default_program_id')).website_id
        if program_website_id:
            return program_website_id
        else:
            Website = self.env['website']
            websites = Website.search([])
            return len(websites) == 1 and websites or Website

    website_id = fields.Many2one('website', required=True, default=_get_default_website_id)
    coupon_id = fields.Many2one('loyalty.card', domain="[('program_id', '=', program_id)]")
    program_id = fields.Many2one('loyalty.program', required=True, domain=[
        '|', ('program_type', '=', 'coupons'), # All coupons programs
        '|', ('trigger', '=', 'with_code'), # All programs that require a code
             ('rule_ids.code', '!=', False), # All programs that can not trigger without a code
    ])
    program_website_id = fields.Many2one('website', string='Program Website', related='program_id.website_id')

    promo_code = fields.Char(compute='_compute_promo_code')
    share_link = fields.Char(compute='_compute_share_link')
    redirect = fields.Char(required=True, default='/shop')

    @api.constrains('coupon_id', 'program_id')
    def _check_program(self):
        if self.filtered(lambda record: not record.coupon_id and record.program_id.program_type == 'coupons'):
            raise ValidationError(_("A coupon is needed for coupon programs."))

    @api.constrains('website_id', 'program_id')
    def _check_website(self):
        if self.filtered(lambda record: record.program_website_id and record.program_website_id != record.website_id):
            raise ValidationError(_("The shared website should correspond to the website of the program."))

    @api.depends('coupon_id.code', 'program_id.rule_ids.code')
    def _compute_promo_code(self):
        for record in self:
            record.promo_code = record.coupon_id.code or record.program_id.rule_ids.filtered('code')[:1].code

    @api.depends('website_id', 'redirect')
    @api.depends_context('use_short_link')
    def _compute_share_link(self):
        for record in self:
            target_url = '{base}/coupon/{code}?{query}'.format(
                base=record.website_id.get_base_url(),
                code=record.promo_code,
                query=url_encode({'r': record.redirect}),
            )

            if record.env.context.get('use_short_link'):
                tracker = self.env['link.tracker'].search([('url', '=', target_url)], limit=1)
                if not tracker:
                    tracker = self.env['link.tracker'].create({'url': target_url})
                record.share_link = tracker.short_url
            else:
                record.share_link = target_url

    def action_generate_short_link(self):
        return {
            'name': _('Share'),
            'type': 'ir.actions.act_window',
            'view_mode': 'form',
            'res_model': 'coupon.share',
            'target': 'new',
            'res_id': self.id,
            'context': {
                'use_short_link': True,
            }
        }

    @api.model
    def create_share_action(self, coupon=None, program=None):
        if bool(program) == bool(coupon):
            raise UserError(_("Provide either a coupon or a program."))

        return {
            'name': _('Share') + f' {self.env["loyalty.program"]._program_items_name().get((program or coupon).program_type, "")}',
            'type': 'ir.actions.act_window',
            'view_mode': 'form',
            'res_model': 'coupon.share',
            'target': 'new',
            'context': {
                'default_program_id': program and program.id or coupon.program_id.id,
                'default_coupon_id': coupon and coupon.id or None,
            }
        }
