# -*- coding: utf-8 -*-
# Copyright 2024-2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)

import base64
import logging
import uuid
from datetime import timedelta

from markupsafe import Markup

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

_logger = logging.getLogger(__name__)

SIGNER_TYPE_SELECTION = [
    ('client', 'Client (Self)'),
    ('spouse', 'Spouse'),
    ('parent', 'Parent'),
    ('legal_guardian', 'Legal Guardian'),
    ('poa', 'Power of Attorney'),
    ('public_trustee', 'Public Trustee'),
]

SIGNER_TYPE_TO_RELATIONSHIP = {
    'spouse': 'Spouse',
    'parent': 'Parent',
    'legal_guardian': 'Legal Guardian',
    'poa': 'Power of Attorney',
    'public_trustee': 'Public Trustee',
}


class Page11SignRequest(models.Model):
    _name = 'fusion.page11.sign.request'
    _description = 'ADP Page 11 Remote Signing Request'
    _inherit = ['fusion.email.builder.mixin']
    _order = 'create_date desc'

    sale_order_id = fields.Many2one(
        'sale.order', string='Sale Order',
        required=True, ondelete='cascade', index=True,
    )
    access_token = fields.Char(
        string='Access Token', required=True, copy=False,
        default=lambda self: str(uuid.uuid4()), index=True,
    )
    state = fields.Selection([
        ('draft', 'Draft'),
        ('sent', 'Sent'),
        ('signed', 'Signed'),
        ('expired', 'Expired'),
        ('cancelled', 'Cancelled'),
    ], string='Status', default='draft', required=True, tracking=True)

    signer_email = fields.Char(string='Recipient Email', required=True)
    signer_type = fields.Selection(
        SIGNER_TYPE_SELECTION, string='Signer Type',
        default='client', required=True,
    )
    signer_name = fields.Char(string='Signer Name')
    signer_relationship = fields.Char(string='Relationship to Client')

    signature_data = fields.Binary(string='Signature', attachment=True)
    signed_pdf = fields.Binary(string='Signed PDF', attachment=True)
    signed_pdf_filename = fields.Char(string='Signed PDF Filename')
    signed_date = fields.Datetime(string='Signed Date')
    sent_date = fields.Datetime(string='Sent Date')
    expiry_date = fields.Datetime(string='Expiry Date')

    consent_declaration_accepted = fields.Boolean(string='Declaration Accepted')
    consent_signed_by = fields.Selection([
        ('applicant', 'Applicant'),
        ('agent', 'Agent'),
    ], string='Signed By')

    client_first_name = fields.Char(string='Client First Name')
    client_last_name = fields.Char(string='Client Last Name')
    client_health_card = fields.Char(string='Health Card Number')
    client_health_card_version = fields.Char(string='Health Card Version')

    agent_first_name = fields.Char(string='Agent First Name')
    agent_last_name = fields.Char(string='Agent Last Name')
    agent_middle_initial = fields.Char(string='Agent Middle Initial')
    agent_phone = fields.Char(string='Agent Phone')
    agent_unit = fields.Char(string='Agent Unit Number')
    agent_street_number = fields.Char(string='Agent Street Number')
    agent_street = fields.Char(string='Agent Street Name')
    agent_city = fields.Char(string='Agent City')
    agent_province = fields.Char(string='Agent Province', default='Ontario')
    agent_postal_code = fields.Char(string='Agent Postal Code')

    custom_message = fields.Text(string='Custom Message')

    company_id = fields.Many2one(
        'res.company', string='Company',
        related='sale_order_id.company_id', store=True,
    )

    def name_get(self):
        return [
            (r.id, f"Page 11 - {r.sale_order_id.name} ({r.state})")
            for r in self
        ]

    def _send_signing_email(self):
        """Build and send the signing request email."""
        self.ensure_one()
        base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
        sign_url = f'{base_url}/page11/sign/{self.access_token}'
        order = self.sale_order_id

        client_name = order.partner_id.name or 'N/A'
        sections = [
            ('Case Details', [
                ('Client', client_name),
                ('Case Reference', order.name),
            ]),
        ]

        if order.x_fc_authorizer_id:
            sections[0][1].append(('Authorizer', order.x_fc_authorizer_id.name))

        if order.x_fc_assessment_start_date:
            sections[0][1].append((
                'Assessment Date',
                order.x_fc_assessment_start_date.strftime('%B %d, %Y'),
            ))

        note_parts = []
        if self.custom_message:
            note_parts.append(self.custom_message)
        days_left = 7
        if self.expiry_date:
            delta = self.expiry_date - fields.Datetime.now()
            days_left = max(1, delta.days)
        note_parts.append(
            f'This link will expire in {days_left} days. '
            'Please complete the signing at your earliest convenience.'
        )
        note_text = '<br/><br/>'.join(note_parts)

        body_html = self._email_build(
            title='Page 11 Signature Required',
            summary=(
                f'{order.company_id.name} requires your signature on the '
                f'ADP Consent and Declaration form for <strong>{client_name}</strong>.'
            ),
            sections=sections,
            note=note_text,
            email_type='info',
            button_url=sign_url,
            button_text='Sign Now',
            sender_name=self.env.user.name,
        )

        mail_values = {
            'subject': f'{order.company_id.name} - Page 11 Signature Required ({order.name})',
            'body_html': body_html,
            'email_to': self.signer_email,
            'email_from': (
                self.env.user.email_formatted
                or order.company_id.email_formatted
            ),
            'auto_delete': True,
        }
        mail = self.env['mail.mail'].sudo().create(mail_values)
        mail.send()

        self.write({
            'state': 'sent',
            'sent_date': fields.Datetime.now(),
        })

        signer_display = self.signer_name or self.signer_email
        order.message_post(
            body=Markup(
                'Page 11 signing request sent to <strong>%s</strong> (%s).'
            ) % (signer_display, self.signer_email),
            message_type='notification',
            subtype_xmlid='mail.mt_note',
        )

    def _generate_signed_pdf(self):
        """Generate the signed Page 11 PDF using the PDF template engine."""
        self.ensure_one()
        order = self.sale_order_id

        assessment = self.env['fusion.assessment'].search([
            ('sale_order_id', '=', order.id),
        ], limit=1, order='create_date desc')

        if assessment:
            ctx = assessment._get_pdf_context()
        else:
            ctx = self._build_pdf_context_from_order()

        if self.client_first_name:
            ctx['client_first_name'] = self.client_first_name
        if self.client_last_name:
            ctx['client_last_name'] = self.client_last_name
        if self.client_health_card:
            ctx['client_health_card'] = self.client_health_card
        if self.client_health_card_version:
            ctx['client_health_card_version'] = self.client_health_card_version

        ctx.update({
            'consent_signed_by': self.consent_signed_by or '',
            'consent_applicant': self.consent_signed_by == 'applicant',
            'consent_agent': self.consent_signed_by == 'agent',
            'consent_declaration_accepted': self.consent_declaration_accepted,
            'consent_date': str(fields.Date.today()),
        })

        if self.consent_signed_by == 'agent':
            ctx.update({
                'agent_first_name': self.agent_first_name or '',
                'agent_last_name': self.agent_last_name or '',
                'agent_middle_initial': self.agent_middle_initial or '',
                'agent_unit': self.agent_unit or '',
                'agent_street_number': self.agent_street_number or '',
                'agent_street_name': self.agent_street or '',
                'agent_city': self.agent_city or '',
                'agent_province': self.agent_province or '',
                'agent_postal_code': self.agent_postal_code or '',
                'agent_home_phone': self.agent_phone or '',
                'agent_relationship': self.signer_relationship or '',
                'agent_rel_spouse': self.signer_type == 'spouse',
                'agent_rel_parent': self.signer_type == 'parent',
                'agent_rel_poa': self.signer_type == 'poa',
                'agent_rel_guardian': self.signer_type in ('legal_guardian', 'public_trustee'),
            })

        signatures = {}
        if self.signature_data:
            signatures['signature_page_11'] = base64.b64decode(self.signature_data)

        template = self.env['fusion.pdf.template'].search([
            ('state', '=', 'active'),
            ('name', 'ilike', 'adp_page_11'),
        ], limit=1)

        if not template:
            template = self.env['fusion.pdf.template'].search([
                ('state', '=', 'active'),
                ('name', 'ilike', 'page 11'),
            ], limit=1)

        if not template:
            _logger.warning("No active PDF template found for Page 11")
            return None

        try:
            pdf_bytes = template.generate_filled_pdf(ctx, signatures)
            if pdf_bytes:
                first, last = order._get_client_name_parts()
                filename = f'{first}_{last}_Page11_Signed.pdf'
                self.write({
                    'signed_pdf': base64.b64encode(pdf_bytes),
                    'signed_pdf_filename': filename,
                })
                return pdf_bytes
        except Exception as e:
            _logger.error("Failed to generate Page 11 PDF: %s", e)
        return None

    def _build_pdf_context_from_order(self):
        """Build a PDF context dict from the sale order when no assessment exists."""
        order = self.sale_order_id
        partner = order.partner_id
        first, last = order._get_client_name_parts()
        return {
            'client_first_name': first,
            'client_last_name': last,
            'client_name': partner.name or '',
            'client_street': partner.street or '',
            'client_city': partner.city or '',
            'client_state': partner.state_id.name if partner.state_id else 'Ontario',
            'client_postal_code': partner.zip or '',
            'client_phone': partner.phone or partner.mobile or '',
            'client_email': partner.email or '',
            'client_type': order.x_fc_client_type or '',
            'client_type_reg': order.x_fc_client_type == 'REG',
            'client_type_ods': order.x_fc_client_type == 'ODS',
            'client_type_acs': order.x_fc_client_type == 'ACS',
            'client_type_owp': order.x_fc_client_type == 'OWP',
            'reference': order.name or '',
            'authorizer_name': order.x_fc_authorizer_id.name if order.x_fc_authorizer_id else '',
            'authorizer_phone': order.x_fc_authorizer_id.phone if order.x_fc_authorizer_id else '',
            'authorizer_email': order.x_fc_authorizer_id.email if order.x_fc_authorizer_id else '',
            'claim_authorization_date': str(order.x_fc_claim_authorization_date) if order.x_fc_claim_authorization_date else '',
            'assessment_start_date': str(order.x_fc_assessment_start_date) if order.x_fc_assessment_start_date else '',
            'assessment_end_date': str(order.x_fc_assessment_end_date) if order.x_fc_assessment_end_date else '',
        }

    def _update_sale_order(self):
        """Copy signing data from this request to the sale order."""
        self.ensure_one()
        order = self.sale_order_id
        vals = {
            'x_fc_page11_signer_type': self.signer_type,
            'x_fc_page11_signer_name': self.signer_name,
            'x_fc_page11_signed_date': fields.Date.today(),
        }
        if self.signer_type != 'client':
            vals['x_fc_page11_signer_relationship'] = (
                self.signer_relationship
                or SIGNER_TYPE_TO_RELATIONSHIP.get(self.signer_type, '')
            )
        if self.signed_pdf:
            vals['x_fc_signed_pages_11_12'] = self.signed_pdf
            vals['x_fc_signed_pages_filename'] = self.signed_pdf_filename

        order.with_context(
            skip_page11_check=True,
            skip_document_chatter=True,
        ).write(vals)

        signer_display = self.signer_name or 'N/A'
        if self.signed_pdf:
            att = self.env['ir.attachment'].sudo().create({
                'name': self.signed_pdf_filename or 'Page11_Signed.pdf',
                'datas': self.signed_pdf,
                'res_model': 'sale.order',
                'res_id': order.id,
                'mimetype': 'application/pdf',
            })
            order.message_post(
                body=Markup(
                    'Page 11 has been signed by <strong>%s</strong> (%s).'
                ) % (signer_display, self.signer_email),
                attachment_ids=[att.id],
                message_type='notification',
                subtype_xmlid='mail.mt_note',
            )
        else:
            order.message_post(
                body=Markup(
                    'Page 11 has been signed by <strong>%s</strong> (%s). '
                    'PDF generation was not available.'
                ) % (signer_display, self.signer_email),
                message_type='notification',
                subtype_xmlid='mail.mt_note',
            )

    def action_cancel(self):
        """Cancel a pending signing request."""
        for rec in self:
            if rec.state in ('draft', 'sent'):
                rec.state = 'cancelled'

    def action_resend(self):
        """Resend the signing email."""
        for rec in self:
            if rec.state in ('sent', 'expired'):
                rec.expiry_date = fields.Datetime.now() + timedelta(days=7)
                rec.access_token = str(uuid.uuid4())
                rec._send_signing_email()

    def action_request_new_signature(self):
        """Create a new signing request (e.g. to re-sign after corrections)."""
        self.ensure_one()
        if self.state == 'signed':
            self.state = 'cancelled'
        return {
            'type': 'ir.actions.act_window',
            'name': 'Request Page 11 Signature',
            'res_model': 'fusion_claims.send.page11.wizard',
            'view_mode': 'form',
            'target': 'new',
            'context': {
                'default_sale_order_id': self.sale_order_id.id,
                'default_signer_email': self.signer_email,
                'default_signer_name': self.signer_name,
                'default_signer_type': self.signer_type,
            },
        }

    @api.model
    def _cron_expire_requests(self):
        """Mark expired unsigned requests."""
        expired = self.search([
            ('state', '=', 'sent'),
            ('expiry_date', '<', fields.Datetime.now()),
        ])
        if expired:
            expired.write({'state': 'expired'})
            _logger.info("Expired %d Page 11 signing requests", len(expired))
