# -*- coding: utf-8 -*-

from odoo import http, fields, _
from odoo.http import request
from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager
from odoo.exceptions import AccessError, MissingError, ValidationError
import json
import base64
import logging
from datetime import datetime
from markupsafe import Markup

_logger = logging.getLogger(__name__)


class AssessmentPortal(CustomerPortal):
    """Portal controller for Assessments"""

    @http.route(['/my/assessments', '/my/assessments/page/<int:page>'], type='http', auth='user', website=True)
    def portal_assessments(self, page=1, search='', state='', sortby='date', **kw):
        """List of assessments"""
        partner = request.env.user.partner_id
        user = request.env.user
        
        if not partner.is_authorizer and not partner.is_sales_rep_portal:
            return request.redirect('/my')
        
        Assessment = request.env['fusion.assessment'].sudo()
        
        # Build domain based on role
        domain = []
        if partner.is_authorizer and partner.is_sales_rep_portal:
            domain = ['|', ('authorizer_id', '=', partner.id), ('sales_rep_id', '=', user.id)]
        elif partner.is_authorizer:
            domain = [('authorizer_id', '=', partner.id)]
        elif partner.is_sales_rep_portal:
            domain = [('sales_rep_id', '=', user.id)]
        
        # Add state filter
        if state:
            domain.append(('state', '=', state))
        
        # Add search filter
        if search:
            domain = domain + [
                '|', '|',
                ('client_name', 'ilike', search),
                ('reference', 'ilike', search),
                ('client_email', 'ilike', search),
            ]
        
        # Sorting
        sortings = {
            'date': {'label': _('Date'), 'order': 'assessment_date desc'},
            'name': {'label': _('Client'), 'order': 'client_name'},
            'reference': {'label': _('Reference'), 'order': 'reference'},
            'state': {'label': _('Status'), 'order': 'state'},
        }
        order = sortings.get(sortby, sortings['date'])['order']
        
        # Pager
        assessment_count = Assessment.search_count(domain)
        pager = portal_pager(
            url='/my/assessments',
            url_args={'search': search, 'state': state, 'sortby': sortby},
            total=assessment_count,
            page=page,
            step=20,
        )
        
        # Get assessments
        assessments = Assessment.search(domain, order=order, limit=20, offset=pager['offset'])
        
        # State options for filter
        state_options = [
            ('', _('All')),
            ('draft', _('In Progress')),
            ('pending_signature', _('Pending Signatures')),
            ('completed', _('Completed')),
            ('cancelled', _('Cancelled')),
        ]
        
        values = {
            'assessments': assessments,
            'pager': pager,
            'search': search,
            'state': state,
            'state_options': state_options,
            'sortby': sortby,
            'sortings': sortings,
            'page_name': 'assessments',
        }
        
        return request.render('fusion_authorizer_portal.portal_assessments', values)

    @http.route('/my/assessment/new', type='http', auth='user', website=True)
    def portal_assessment_new(self, **kw):
        """Start a new assessment"""
        partner = request.env.user.partner_id
        user = request.env.user
        
        if not partner.is_authorizer and not partner.is_sales_rep_portal:
            return request.redirect('/my')
        
        # Get list of authorizers for dropdown (if sales rep starting assessment)
        authorizers = request.env['res.partner'].sudo().search([
            ('is_authorizer', '=', True),
        ])
        
        values = {
            'partner': partner,
            'user': user,
            'authorizers': authorizers,
            'countries': request.env['res.country'].sudo().search([]),
            'default_country': request.env.ref('base.ca', raise_if_not_found=False),
            'page_name': 'assessment_new',
        }
        
        return request.render('fusion_authorizer_portal.portal_assessment_form', values)

    @http.route('/my/assessment/<int:assessment_id>', type='http', auth='user', website=True)
    def portal_assessment_view(self, assessment_id, **kw):
        """View/edit an assessment"""
        partner = request.env.user.partner_id
        user = request.env.user
        
        if not partner.is_authorizer and not partner.is_sales_rep_portal:
            return request.redirect('/my')
        
        try:
            assessment = request.env['fusion.assessment'].sudo().browse(assessment_id)
            if not assessment.exists():
                raise MissingError(_('Assessment not found.'))
            
            # Check access
            has_access = (
                (partner.is_authorizer and assessment.authorizer_id.id == partner.id) or
                (partner.is_sales_rep_portal and assessment.sales_rep_id.id == user.id)
            )
            if not has_access:
                raise AccessError(_('You do not have access to this assessment.'))
                
        except (AccessError, MissingError):
            return request.redirect('/my/assessments')
        
        # Get list of authorizers for dropdown
        authorizers = request.env['res.partner'].sudo().search([
            ('is_authorizer', '=', True),
        ])
        
        # Get assessment photos
        photos = request.env['ir.attachment'].sudo().search([
            ('res_model', '=', 'fusion.assessment'),
            ('res_id', '=', assessment.id),
            ('mimetype', 'like', 'image/%'),
        ])

        values = {
            'assessment': assessment,
            'partner': partner,
            'user': user,
            'authorizers': authorizers,
            'countries': request.env['res.country'].sudo().search([]),
            'page_name': 'assessment_edit',
            'is_readonly': assessment.state in ['completed', 'cancelled'],
            'photos': photos,
        }
        
        return request.render('fusion_authorizer_portal.portal_assessment_form', values)

    @http.route('/my/assessment/save', type='http', auth='user', website=True, methods=['POST'], csrf=True)
    def portal_assessment_save(self, assessment_id=None, **kw):
        """Save assessment data (create or update)"""
        partner = request.env.user.partner_id
        user = request.env.user
        
        if not partner.is_authorizer and not partner.is_sales_rep_portal:
            return request.redirect('/my')
        
        Assessment = request.env['fusion.assessment'].sudo()
        
        # Prepare values
        vals = {
            'client_name': kw.get('client_name', ''),
            'client_first_name': kw.get('client_first_name', ''),
            'client_last_name': kw.get('client_last_name', ''),
            'client_street': kw.get('client_street', ''),
            'client_unit': kw.get('client_unit', ''),
            'client_city': kw.get('client_city', ''),
            'client_state': kw.get('client_state', 'Ontario'),
            'client_postal_code': kw.get('client_postal_code', ''),
            'client_phone': kw.get('client_phone', ''),
            'client_mobile': kw.get('client_mobile', ''),
            'client_email': kw.get('client_email', ''),
            'client_reference_1': kw.get('client_reference_1', ''),
            'client_reference_2': kw.get('client_reference_2', ''),
            'assessment_location': kw.get('assessment_location', 'home'),
            'assessment_location_notes': kw.get('assessment_location_notes', ''),
        }
        
        # Wheelchair specifications
        float_fields = [
            'seat_width', 'seat_depth', 'seat_to_floor_height', 'back_height',
            'armrest_height', 'footrest_length', 'overall_width', 'overall_length',
            'overall_height', 'seat_angle', 'back_angle', 'client_weight', 'client_height'
        ]
        for field in float_fields:
            if kw.get(field):
                try:
                    vals[field] = float(kw.get(field))
                except (ValueError, TypeError):
                    pass
        
        # Selection fields
        selection_fields = ['cushion_type', 'backrest_type', 'frame_type', 'wheel_type']
        for field in selection_fields:
            if kw.get(field):
                vals[field] = kw.get(field)
        
        # Text fields
        text_fields = ['cushion_notes', 'backrest_notes', 'frame_notes', 'wheel_notes',
                      'mobility_notes', 'accessibility_notes', 'special_requirements', 'diagnosis']
        for field in text_fields:
            if kw.get(field):
                vals[field] = kw.get(field)
        
        # Authorizer
        if kw.get('authorizer_id'):
            try:
                vals['authorizer_id'] = int(kw.get('authorizer_id'))
            except (ValueError, TypeError):
                pass
        
        # Country
        if kw.get('client_country_id'):
            try:
                vals['client_country_id'] = int(kw.get('client_country_id'))
            except (ValueError, TypeError):
                pass
        
        try:
            if assessment_id and assessment_id != 'None':
                # Update existing
                assessment = Assessment.browse(int(assessment_id))
                if not assessment.exists():
                    raise MissingError(_('Assessment not found.'))
                
                # Check access
                has_access = (
                    (partner.is_authorizer and assessment.authorizer_id.id == partner.id) or
                    (partner.is_sales_rep_portal and assessment.sales_rep_id.id == user.id)
                )
                if not has_access:
                    raise AccessError(_('You do not have access to this assessment.'))
                
                if assessment.state not in ['draft', 'pending_signature']:
                    raise ValidationError(_('Cannot modify a completed or cancelled assessment.'))
                
                assessment.write(vals)
                _logger.info(f"Updated assessment {assessment.reference}")
                
            else:
                # Create new
                vals['sales_rep_id'] = user.id
                if partner.is_authorizer:
                    vals['authorizer_id'] = partner.id
                
                assessment = Assessment.create(vals)
                _logger.info(f"Created new assessment {assessment.reference}")
            
            # Redirect based on action
            action = kw.get('action', 'save')
            if action == 'save_signatures':
                return request.redirect(f'/my/assessment/{assessment.id}/signatures')
            elif action == 'save_exit':
                return request.redirect('/my/assessments')
            else:
                return request.redirect(f'/my/assessment/{assessment.id}')
                
        except Exception as e:
            _logger.error(f"Error saving assessment: {e}")
            return request.redirect('/my/assessments')

    @http.route('/my/assessment/<int:assessment_id>/signatures', type='http', auth='user', website=True)
    def portal_assessment_signatures(self, assessment_id, **kw):
        """Signature capture page"""
        partner = request.env.user.partner_id
        user = request.env.user
        
        if not partner.is_authorizer and not partner.is_sales_rep_portal:
            return request.redirect('/my')
        
        try:
            assessment = request.env['fusion.assessment'].sudo().browse(assessment_id)
            if not assessment.exists():
                raise MissingError(_('Assessment not found.'))
            
            # Check access
            has_access = (
                (partner.is_authorizer and assessment.authorizer_id.id == partner.id) or
                (partner.is_sales_rep_portal and assessment.sales_rep_id.id == user.id)
            )
            if not has_access:
                raise AccessError(_('You do not have access to this assessment.'))
                
        except (AccessError, MissingError):
            return request.redirect('/my/assessments')
        
        values = {
            'assessment': assessment,
            'partner': partner,
            'page_name': 'assessment_signatures',
        }
        
        return request.render('fusion_authorizer_portal.portal_assessment_signatures', values)

    @http.route('/my/assessment/<int:assessment_id>/save_signature', type='jsonrpc', auth='user')
    def portal_save_signature(self, assessment_id, signature_type='', signature_data='', signer_name='', **kw):
        """Save a signature (AJAX)"""
        partner = request.env.user.partner_id
        user = request.env.user
        
        if not partner.is_authorizer and not partner.is_sales_rep_portal:
            return {'success': False, 'error': 'Access denied'}
        
        try:
            assessment = request.env['fusion.assessment'].sudo().browse(assessment_id)
            if not assessment.exists():
                return {'success': False, 'error': 'Assessment not found'}
            
            # Check access
            has_access = (
                (partner.is_authorizer and assessment.authorizer_id.id == partner.id) or
                (partner.is_sales_rep_portal and assessment.sales_rep_id.id == user.id)
            )
            if not has_access:
                return {'success': False, 'error': 'Access denied'}
            
            if not signature_data:
                return {'success': False, 'error': 'No signature data provided'}
            
            # Remove data URL prefix if present
            if signature_data.startswith('data:image'):
                signature_data = signature_data.split(',')[1]
            
            vals = {}
            if signature_type == 'page_11':
                vals = {
                    'signature_page_11': signature_data,
                    'signature_page_11_name': signer_name,
                    'signature_page_11_date': datetime.now(),
                }
            elif signature_type == 'page_12':
                vals = {
                    'signature_page_12': signature_data,
                    'signature_page_12_name': signer_name,
                    'signature_page_12_date': datetime.now(),
                }
            else:
                return {'success': False, 'error': 'Invalid signature type'}
            
            assessment.write(vals)
            
            # Update state if needed
            if assessment.state == 'draft':
                assessment.state = 'pending_signature'
            
            return {
                'success': True,
                'signatures_complete': assessment.signatures_complete,
            }
            
        except Exception as e:
            _logger.error(f"Error saving signature: {e}")
            return {'success': False, 'error': str(e)}

    @http.route('/my/assessment/<int:assessment_id>/complete', type='http', auth='user', website=True, methods=['POST'], csrf=True)
    def portal_assessment_complete(self, assessment_id, **kw):
        """Complete the assessment"""
        partner = request.env.user.partner_id
        user = request.env.user
        
        if not partner.is_authorizer and not partner.is_sales_rep_portal:
            return request.redirect('/my')
        
        try:
            assessment = request.env['fusion.assessment'].sudo().browse(assessment_id)
            if not assessment.exists():
                raise MissingError(_('Assessment not found.'))
            
            # Check access
            has_access = (
                (partner.is_authorizer and assessment.authorizer_id.id == partner.id) or
                (partner.is_sales_rep_portal and assessment.sales_rep_id.id == user.id)
            )
            if not has_access:
                raise AccessError(_('You do not have access to this assessment.'))
            
            # Complete the assessment
            result = assessment.action_complete()
            
            # Redirect to the created sale order or assessments list
            if assessment.sale_order_id:
                return request.redirect('/my/assessments?message=completed')
            else:
                return request.redirect('/my/assessments')
                
        except ValidationError as e:
            _logger.warning(f"Validation error completing assessment: {e}")
            return request.redirect(f'/my/assessment/{assessment_id}/signatures?error=signatures_required')
        except Exception as e:
            _logger.error(f"Error completing assessment: {e}")
            return request.redirect(f'/my/assessment/{assessment_id}?error=1')

    # ==========================================================================
    # EXPRESS ASSESSMENT FORM ROUTES
    # ==========================================================================

    @http.route('/my/assessment/express', type='http', auth='user', website=True)
    def portal_assessment_express_new(self, **kw):
        """Start a new express assessment (Page 1 - Equipment Selection)"""
        partner = request.env.user.partner_id
        user = request.env.user
        
        if not partner.is_sales_rep_portal:
            return request.redirect('/my')
        
        # Get list of authorizers for dropdown
        authorizers = request.env['res.partner'].sudo().search([
            ('is_authorizer', '=', True),
        ], order='name')
        
        # JSON-safe authorizer list for searchable dropdown (Markup so t-out won't escape)
        authorizers_json = Markup(json.dumps([
            {'id': a.id, 'name': a.name, 'email': a.email or ''}
            for a in authorizers
        ]))
        
        # Get existing clients for dropdown
        clients = request.env['res.partner'].sudo().search([
            ('customer_rank', '>', 0),
        ], order='name', limit=500)
        
        # Get Google Maps API key
        ICP = request.env['ir.config_parameter'].sudo()
        google_maps_api_key = ICP.get_param('fusion_claims.google_maps_api_key', '')
        
        values = {
            'partner': partner,
            'user': user,
            'authorizers': authorizers,
            'authorizers_json': authorizers_json,
            'clients': clients,
            'countries': request.env['res.country'].sudo().search([]),
            'provinces': self._get_canadian_provinces(),
            'default_country': request.env.ref('base.ca', raise_if_not_found=False),
            'page_name': 'assessment_express',
            'current_page': 1,
            'total_pages': 2,
            'assessment': None,
            'google_maps_api_key': google_maps_api_key,
        }
        
        return request.render('fusion_authorizer_portal.portal_assessment_express', values)

    @http.route('/my/assessment/express/<int:assessment_id>', type='http', auth='user', website=True)
    def portal_assessment_express_edit(self, assessment_id, page=1, **kw):
        """Continue/edit an express assessment"""
        partner = request.env.user.partner_id
        user = request.env.user
        
        if not partner.is_sales_rep_portal:
            return request.redirect('/my')
        
        try:
            assessment = request.env['fusion.assessment'].sudo().browse(assessment_id)
            if not assessment.exists():
                raise MissingError(_('Assessment not found.'))
            
            # Check access - must be the sales rep who created it
            if assessment.sales_rep_id.id != user.id:
                raise AccessError(_('You do not have access to this assessment.'))
            
            if assessment.state in ['cancelled']:
                return request.redirect('/my/assessments')
                
        except (AccessError, MissingError):
            return request.redirect('/my/assessments')
        
        # Get list of authorizers for dropdown
        authorizers = request.env['res.partner'].sudo().search([
            ('is_authorizer', '=', True),
        ], order='name')
        
        # JSON-safe authorizer list for searchable dropdown (Markup so t-out won't escape)
        authorizers_json = Markup(json.dumps([
            {'id': a.id, 'name': a.name, 'email': a.email or ''}
            for a in authorizers
        ]))
        
        # Get existing clients for dropdown
        clients = request.env['res.partner'].sudo().search([
            ('customer_rank', '>', 0),
        ], order='name', limit=500)
        
        try:
            current_page = int(page)
        except (ValueError, TypeError):
            current_page = 1
        
        # Get Google Maps API key
        ICP = request.env['ir.config_parameter'].sudo()
        google_maps_api_key = ICP.get_param('fusion_claims.google_maps_api_key', '')
        
        values = {
            'partner': partner,
            'user': user,
            'assessment': assessment,
            'authorizers': authorizers,
            'authorizers_json': authorizers_json,
            'clients': clients,
            'countries': request.env['res.country'].sudo().search([]),
            'provinces': self._get_canadian_provinces(),
            'default_country': request.env.ref('base.ca', raise_if_not_found=False),
            'page_name': 'assessment_express',
            'current_page': current_page,
            'total_pages': 2,
            'google_maps_api_key': google_maps_api_key,
        }
        
        return request.render('fusion_authorizer_portal.portal_assessment_express', values)

    @http.route('/my/assessment/express/save', type='http', auth='user', website=True, methods=['POST'], csrf=True)
    def portal_assessment_express_save(self, **kw):
        """Save express assessment data (create or update)"""
        partner = request.env.user.partner_id
        user = request.env.user
        
        if not partner.is_sales_rep_portal:
            return request.redirect('/my')
        
        Assessment = request.env['fusion.assessment'].sudo()
        assessment_id = kw.get('assessment_id')
        current_page = int(kw.get('current_page', 1))
        action = kw.get('action', 'next')  # next, back, save, submit
        
        # Build values from form
        vals = self._build_express_assessment_vals(kw)
        
        try:
            if assessment_id and assessment_id != 'None' and assessment_id != '':
                # Update existing
                assessment = Assessment.browse(int(assessment_id))
                if not assessment.exists():
                    raise MissingError(_('Assessment not found.'))
                
                if assessment.sales_rep_id.id != user.id:
                    raise AccessError(_('You do not have access to this assessment.'))
                
                if assessment.state == 'completed':
                    # Allow updating ONLY consent/signature fields on completed assessments
                    consent_fields = {
                        'consent_signed_by', 'consent_declaration_accepted', 'consent_date',
                        'agent_relationship', 'agent_first_name', 'agent_last_name',
                        'agent_middle_initial', 'agent_unit', 'agent_street_number',
                        'agent_street_name', 'agent_city', 'agent_province',
                        'agent_postal_code', 'agent_home_phone', 'agent_business_phone',
                        'agent_phone_ext',
                    }
                    consent_vals = {k: v for k, v in vals.items() if k in consent_fields}
                    if consent_vals:
                        assessment.write(consent_vals)
                        _logger.info(f"Updated consent fields on completed assessment {assessment.reference}")
                elif assessment.state == 'cancelled':
                    raise ValidationError(_('Cannot modify a cancelled assessment.'))
                else:
                    # Draft - allow full update
                    assessment.write(vals)
                    _logger.info(f"Updated express assessment {assessment.reference}")
            else:
                # Create new
                vals['sales_rep_id'] = user.id
                vals['state'] = 'draft'
                assessment = Assessment.create(vals)
                _logger.info(f"Created new express assessment {assessment.reference}")
            
            # Handle photo uploads
            uploaded_photos = request.httprequest.files.getlist('assessment_photos')
            if uploaded_photos:
                for photo_file in uploaded_photos:
                    if photo_file and photo_file.filename:
                        try:
                            file_content = photo_file.read()
                            file_base64 = base64.b64encode(file_content)
                            
                            # Create attachment linked to assessment
                            attachment = request.env['ir.attachment'].sudo().create({
                                'name': photo_file.filename,
                                'type': 'binary',
                                'datas': file_base64,
                                'res_model': 'fusion.assessment',
                                'res_id': assessment.id,
                                'mimetype': photo_file.content_type or 'image/jpeg',
                            })
                            _logger.info(f"Uploaded assessment photo: {photo_file.filename}")
                        except Exception as e:
                            _logger.error(f"Error uploading photo {photo_file.filename}: {e}")
            
            # ===== Handle Page 11 signature capture =====
            signature_data = kw.get('signature_page_11_data', '')
            if signature_data and signature_data.startswith('data:image/'):
                try:
                    # Strip data URL prefix: "data:image/png;base64,..."
                    sig_base64 = signature_data.split(',', 1)[1]
                    sig_vals = {
                        'signature_page_11': sig_base64,
                        'signature_page_11_date': fields.Datetime.now(),
                    }
                    # Set signer name
                    if kw.get('consent_signed_by') == 'agent' and kw.get('agent_first_name'):
                        sig_vals['signature_page_11_name'] = (
                            f"{kw.get('agent_first_name', '')} {kw.get('agent_last_name', '')}"
                        ).strip()
                    else:
                        sig_vals['signature_page_11_name'] = (
                            f"{kw.get('client_first_name', '')} {kw.get('client_last_name', '')}"
                        ).strip()
                    assessment.write(sig_vals)
                    _logger.info(f"Saved Page 11 signature for assessment {assessment.reference}")
                except Exception as e:
                    _logger.error(f"Error saving Page 11 signature: {e}")

            # Handle navigation
            if action == 'submit':
                # If already completed, we just saved consent/signature above -- redirect with success
                if assessment.state == 'completed':
                    # Generate filled PDF if signature was added
                    if assessment.signature_page_11 and assessment.consent_declaration_accepted:
                        try:
                            pdf_bytes = assessment.generate_template_pdf('Page 11')
                            if pdf_bytes:
                                import base64 as b64
                                assessment.write({
                                    'signed_page_11_pdf': b64.b64encode(pdf_bytes),
                                    'signed_page_11_pdf_filename': f'ADP_Page11_{assessment.reference}.pdf',
                                })
                                # Update sale order too
                                # Issue 8 fix: bypass document lock since this is a portal
                                # re-signing on an already-completed assessment (SO may have
                                # progressed past 'submitted' where the lock kicks in)
                                if assessment.sale_order_id:
                                    assessment.sale_order_id.with_context(
                                        skip_document_lock_validation=True
                                    ).write({
                                        'x_fc_signed_pages_11_12': b64.b64encode(pdf_bytes),
                                        'x_fc_signed_pages_filename': f'ADP_Page11_{assessment.reference}.pdf',
                                    })
                                _logger.info(f"Generated Page 11 PDF for completed assessment {assessment.reference}")
                        except Exception as pdf_e:
                            _logger.warning(f"PDF generation failed (non-blocking): {pdf_e}")

                    # Post consent & signature info to sale order chatter
                    if assessment.sale_order_id and assessment.signature_page_11:
                        try:
                            from markupsafe import Markup
                            signer = assessment.signature_page_11_name or 'Unknown'
                            signed_by = 'Applicant' if assessment.consent_signed_by == 'applicant' else 'Agent'
                            consent_date = str(assessment.consent_date) if assessment.consent_date else 'N/A'

                            # Create signature as attachment
                            sig_att = request.env['ir.attachment'].sudo().create({
                                'name': f'Page11_Signature_{assessment.reference}.png',
                                'type': 'binary',
                                'datas': assessment.signature_page_11,
                                'res_model': 'sale.order',
                                'res_id': assessment.sale_order_id.id,
                                'mimetype': 'image/png',
                            })

                            body = Markup(
                                '<div class="alert alert-success" role="alert">'
                                '<h5 class="alert-heading"><i class="fa fa-file-text"/> Page 11 Consent &amp; Signature</h5>'
                                '<ul class="mb-0">'
                                f'<li><strong>Signed by:</strong> {signer} ({signed_by})</li>'
                                f'<li><strong>Consent date:</strong> {consent_date}</li>'
                                f'<li><strong>Declaration accepted:</strong> Yes</li>'
                                '</ul>'
                                '</div>'
                            )
                            assessment.sale_order_id.message_post(
                                body=body,
                                message_type='comment',
                                subtype_xmlid='mail.mt_note',
                                attachment_ids=[sig_att.id],
                            )
                            _logger.info(f"Posted Page 11 consent info to SO {assessment.sale_order_id.name}")
                        except Exception as chat_e:
                            _logger.warning(f"Failed to post consent to chatter: {chat_e}")

                    so_id = assessment.sale_order_id.id if assessment.sale_order_id else ''
                    return request.redirect(f'/my/assessments?message=completed&so={so_id}')
                
                # Complete the express assessment
                try:
                    sale_order = assessment.action_complete_express()
                    
                    # Post assessment photos to sale order chatter
                    photo_attachments = request.env['ir.attachment'].sudo().search([
                        ('res_model', '=', 'fusion.assessment'),
                        ('res_id', '=', assessment.id),
                        ('mimetype', 'like', 'image/%'),
                    ])
                    if photo_attachments:
                        # Copy attachments to sale order
                        attachment_ids = []
                        for att in photo_attachments:
                            new_att = att.copy({
                                'res_model': 'sale.order',
                                'res_id': sale_order.id,
                            })
                            attachment_ids.append(new_att.id)
                        
                        # Post message to chatter with photos
                        sale_order.message_post(
                            body=Markup(
                                '<p><strong>Assessment Photos</strong><br/>'
                                'Photos from assessment %s by %s</p>'
                            ) % (assessment.reference, request.env.user.name),
                            message_type='comment',
                            subtype_xmlid='mail.mt_comment',
                            attachment_ids=attachment_ids,
                        )
                        _logger.info(f"Posted {len(attachment_ids)} assessment photos to sale order {sale_order.name}")
                    
                    # Process loaner checkout if loaner data was submitted
                    loaner_product_id = kw.get('loaner_product_id')
                    loaner_checkout_flag = kw.get('loaner_checkout', '0')
                    if loaner_product_id and loaner_checkout_flag == '1':
                        try:
                            loaner_vals = {
                                'product_id': int(loaner_product_id),
                                'sale_order_id': sale_order.id,
                                'partner_id': sale_order.partner_id.id,
                                'loaner_period_days': int(kw.get('loaner_period_days', 7)),
                                'checkout_condition': kw.get('loaner_condition', 'good'),
                                'checkout_notes': kw.get('loaner_notes', ''),
                                'sales_rep_id': request.env.user.id,
                            }
                            if sale_order.x_fc_authorizer_id:
                                loaner_vals['authorizer_id'] = sale_order.x_fc_authorizer_id.id
                            if sale_order.partner_shipping_id:
                                loaner_vals['delivery_address'] = sale_order.partner_shipping_id.contact_address
                            loaner_lot = kw.get('loaner_lot_id')
                            if loaner_lot:
                                loaner_vals['lot_id'] = int(loaner_lot)
                            checkout = request.env['fusion.loaner.checkout'].sudo().create(loaner_vals)
                            checkout.action_checkout()
                            _logger.info(f"Created loaner checkout {checkout.name} for SO {sale_order.name}")
                        except Exception as le:
                            _logger.error(f"Error creating loaner checkout: {le}")

                    # ===== Generate filled Page 11 PDF if signature exists =====
                    if assessment.signature_page_11 and assessment.consent_declaration_accepted:
                        try:
                            pdf_bytes = assessment.generate_template_pdf('Page 11')
                            if pdf_bytes:
                                import base64 as b64
                                assessment.write({
                                    'signed_page_11_pdf': b64.b64encode(pdf_bytes),
                                    'signed_page_11_pdf_filename': f'ADP_Page11_{assessment.reference}.pdf',
                                })
                                # Also store on sale order
                                # Issue 8 fix: bypass document lock for portal writes
                                sale_order.with_context(
                                    skip_document_lock_validation=True
                                ).write({
                                    'x_fc_signed_pages_11_12': b64.b64encode(pdf_bytes),
                                    'x_fc_signed_pages_filename': f'ADP_Page11_{assessment.reference}.pdf',
                                })
                                _logger.info(f"Generated Page 11 PDF for assessment {assessment.reference}")
                        except Exception as pdf_e:
                            _logger.warning(f"PDF generation failed (non-blocking): {pdf_e}")

                    return request.redirect(f'/my/assessments?message=completed&so={sale_order.id}')
                except Exception as e:
                    _logger.error(f"Error completing express assessment: {e}")
                    return request.redirect(f'/my/assessment/express/{assessment.id}?error={str(e)}')
            elif action == 'start_over':
                # Cancel and start fresh
                if assessment_id and assessment_id != 'None':
                    assessment.unlink()
                return request.redirect('/my/assessment/express')
            else:
                # Just save
                return request.redirect(f'/my/assessment/express/{assessment.id}?page={current_page}')
                
        except Exception as e:
            _logger.error(f"Error saving express assessment: {e}")
            if assessment_id and assessment_id != 'None':
                return request.redirect(f'/my/assessment/express/{assessment_id}?page={current_page}&error=1')
            return request.redirect('/my/assessment/express?error=1')

    def _build_express_assessment_vals(self, kw):
        """Build values dict from express form POST data"""
        vals = {}
        
        # Equipment type
        if kw.get('equipment_type'):
            vals['equipment_type'] = kw.get('equipment_type')
        
        # Equipment sub-types
        if kw.get('rollator_type'):
            vals['rollator_type'] = kw.get('rollator_type')
        if kw.get('wheelchair_type'):
            vals['wheelchair_type'] = kw.get('wheelchair_type')
        if kw.get('powerchair_type'):
            vals['powerchair_type'] = kw.get('powerchair_type')
        
        # Float measurements
        float_fields = [
            'rollator_handle_height', 'rollator_seat_height',
            'seat_width', 'seat_depth', 'seat_to_floor_height', 'back_height',
            'legrest_length', 'cane_height', 'client_weight',
        ]
        for field in float_fields:
            if kw.get(field):
                try:
                    vals[field] = float(kw.get(field))
                except (ValueError, TypeError):
                    pass
        
        # Checkbox options - collect as comma-separated strings
        # Rollator addons
        rollator_addons = kw.getlist('rollator_addons') if hasattr(kw, 'getlist') else []
        if not rollator_addons and 'rollator_addons' in kw:
            rollator_addons = [kw.get('rollator_addons')] if kw.get('rollator_addons') else []
        if rollator_addons:
            vals['rollator_addons'] = ', '.join(rollator_addons)
        
        # Wheelchair options
        frame_options = kw.getlist('frame_options') if hasattr(kw, 'getlist') else []
        if not frame_options and 'frame_options' in kw:
            frame_options = [kw.get('frame_options')] if kw.get('frame_options') else []
        if frame_options:
            vals['frame_options'] = ', '.join(frame_options)
        
        wheel_options = kw.getlist('wheel_options') if hasattr(kw, 'getlist') else []
        if not wheel_options and 'wheel_options' in kw:
            wheel_options = [kw.get('wheel_options')] if kw.get('wheel_options') else []
        if wheel_options:
            vals['wheel_options'] = ', '.join(wheel_options)
        
        legrest_options = kw.getlist('legrest_options') if hasattr(kw, 'getlist') else []
        if not legrest_options and 'legrest_options' in kw:
            legrest_options = [kw.get('legrest_options')] if kw.get('legrest_options') else []
        if legrest_options:
            vals['legrest_options'] = ', '.join(legrest_options)
        
        additional_adp_options = kw.getlist('additional_adp_options') if hasattr(kw, 'getlist') else []
        if not additional_adp_options and 'additional_adp_options' in kw:
            additional_adp_options = [kw.get('additional_adp_options')] if kw.get('additional_adp_options') else []
        if additional_adp_options:
            vals['additional_adp_options'] = ', '.join(additional_adp_options)
        
        # Powerchair options
        powerchair_options = kw.getlist('powerchair_options') if hasattr(kw, 'getlist') else []
        if not powerchair_options and 'powerchair_options' in kw:
            powerchair_options = [kw.get('powerchair_options')] if kw.get('powerchair_options') else []
        if powerchair_options:
            vals['powerchair_options'] = ', '.join(powerchair_options)
        
        specialty_controls = kw.getlist('specialty_controls') if hasattr(kw, 'getlist') else []
        if not specialty_controls and 'specialty_controls' in kw:
            specialty_controls = [kw.get('specialty_controls')] if kw.get('specialty_controls') else []
        if specialty_controls:
            vals['specialty_controls'] = ', '.join(specialty_controls)
        
        # Seatbelt type
        if kw.get('seatbelt_type'):
            vals['seatbelt_type'] = kw.get('seatbelt_type')
        
        # Additional customization
        if kw.get('additional_customization'):
            vals['additional_customization'] = kw.get('additional_customization')
        
        # Cushion and backrest
        if kw.get('cushion_info'):
            vals['cushion_info'] = kw.get('cushion_info')
        if kw.get('backrest_info'):
            vals['backrest_info'] = kw.get('backrest_info')
        
        # Client type
        if kw.get('client_type'):
            vals['client_type'] = kw.get('client_type')
        
        # Client info (Page 2)
        if kw.get('client_first_name'):
            vals['client_first_name'] = kw.get('client_first_name')
        if kw.get('client_middle_name'):
            vals['client_middle_name'] = kw.get('client_middle_name')
        if kw.get('client_last_name'):
            vals['client_last_name'] = kw.get('client_last_name')
        
        # Build full client name
        name_parts = []
        if kw.get('client_first_name'):
            name_parts.append(kw.get('client_first_name'))
        if kw.get('client_middle_name'):
            name_parts.append(kw.get('client_middle_name'))
        if kw.get('client_last_name'):
            name_parts.append(kw.get('client_last_name'))
        if name_parts:
            vals['client_name'] = ' '.join(name_parts)
        
        # Health card
        if kw.get('client_health_card'):
            vals['client_health_card'] = kw.get('client_health_card')
        if kw.get('client_health_card_version'):
            vals['client_health_card_version'] = kw.get('client_health_card_version')
        
        # Address
        if kw.get('client_street'):
            vals['client_street'] = kw.get('client_street')
        if kw.get('client_unit'):
            vals['client_unit'] = kw.get('client_unit')
        if kw.get('client_city'):
            vals['client_city'] = kw.get('client_city')
        if kw.get('client_state'):
            vals['client_state'] = kw.get('client_state')
        if kw.get('client_postal_code'):
            vals['client_postal_code'] = kw.get('client_postal_code')
        if kw.get('client_country_id'):
            try:
                vals['client_country_id'] = int(kw.get('client_country_id'))
            except (ValueError, TypeError):
                pass
        
        # Contact
        if kw.get('client_phone'):
            vals['client_phone'] = kw.get('client_phone')
        if kw.get('client_email'):
            vals['client_email'] = kw.get('client_email')
        
        # Dates
        date_fields = ['assessment_start_date', 'assessment_end_date', 'claim_authorization_date', 'previous_funding_date']
        for field in date_fields:
            if kw.get(field):
                try:
                    vals[field] = kw.get(field)
                except (ValueError, TypeError):
                    pass
        
        # Reason for application
        if kw.get('reason_for_application'):
            vals['reason_for_application'] = kw.get('reason_for_application')
        
        # Authorizer
        if kw.get('authorizer_id'):
            try:
                vals['authorizer_id'] = int(kw.get('authorizer_id'))
            except (ValueError, TypeError):
                pass
        
        # Existing partner selection
        if kw.get('partner_id'):
            try:
                partner_id = int(kw.get('partner_id'))
                if partner_id > 0:
                    vals['partner_id'] = partner_id
                    vals['create_new_partner'] = False
                else:
                    vals['create_new_partner'] = True
            except (ValueError, TypeError):
                vals['create_new_partner'] = True
        
        # ===== PAGE 11: Consent & Declaration fields =====
        if kw.get('consent_signed_by'):
            vals['consent_signed_by'] = kw.get('consent_signed_by')

        if kw.get('consent_declaration_accepted'):
            vals['consent_declaration_accepted'] = True

        if kw.get('consent_date'):
            try:
                vals['consent_date'] = kw.get('consent_date')
            except (ValueError, TypeError):
                pass

        # Agent fields (only relevant when consent_signed_by == 'agent')
        agent_fields = [
            'agent_relationship', 'agent_first_name', 'agent_last_name',
            'agent_middle_initial', 'agent_unit', 'agent_street_number',
            'agent_street_name', 'agent_city', 'agent_province',
            'agent_postal_code', 'agent_home_phone', 'agent_business_phone',
            'agent_phone_ext',
        ]
        for field in agent_fields:
            if kw.get(field):
                vals[field] = kw.get(field)

        return vals

    def _get_canadian_provinces(self):
        """Return list of Canadian provinces for dropdown"""
        return [
            ('Ontario', 'Ontario'),
            ('Quebec', 'Quebec'),
            ('British Columbia', 'British Columbia'),
            ('Alberta', 'Alberta'),
            ('Manitoba', 'Manitoba'),
            ('Saskatchewan', 'Saskatchewan'),
            ('Nova Scotia', 'Nova Scotia'),
            ('New Brunswick', 'New Brunswick'),
            ('Newfoundland and Labrador', 'Newfoundland and Labrador'),
            ('Prince Edward Island', 'Prince Edward Island'),
            ('Northwest Territories', 'Northwest Territories'),
            ('Yukon', 'Yukon'),
            ('Nunavut', 'Nunavut'),
        ]

    # =========================================================================
    # LOANER PORTAL ROUTES
    # =========================================================================

    @http.route('/my/loaner/categories', type='jsonrpc', auth='user', website=True)
    def portal_loaner_categories(self, **kw):
        """Return loaner product categories."""
        parent = request.env.ref('fusion_claims.product_category_loaner', raise_if_not_found=False)
        if not parent:
            return []
        categories = request.env['product.category'].sudo().search([
            ('parent_id', '=', parent.id),
        ], order='name')
        return [{'id': c.id, 'name': c.name} for c in categories]

    @http.route('/my/loaner/products', type='jsonrpc', auth='user', website=True)
    def portal_loaner_products(self, **kw):
        """Return available loaner products and their serial numbers."""
        domain = [('x_fc_can_be_loaned', '=', True)]
        category_id = kw.get('category_id')
        if category_id:
            domain.append(('categ_id', '=', int(category_id)))

        products = request.env['product.product'].sudo().search(domain)
        loaner_location = request.env.ref('fusion_claims.stock_location_loaner', raise_if_not_found=False)

        result = []
        for p in products:
            lots = []
            if loaner_location:
                quants = request.env['stock.quant'].sudo().search([
                    ('product_id', '=', p.id),
                    ('location_id', '=', loaner_location.id),
                    ('quantity', '>', 0),
                ])
                for q in quants:
                    if q.lot_id:
                        lots.append({'id': q.lot_id.id, 'name': q.lot_id.name})
            result.append({
                'id': p.id,
                'name': p.name,
                'category_id': p.categ_id.id,
                'period_days': p.product_tmpl_id.x_fc_loaner_period_days or 7,
                'lots': lots,
            })
        return result

    @http.route('/my/loaner/locations', type='jsonrpc', auth='user', website=True)
    def portal_loaner_locations(self, **kw):
        """Return internal stock locations for return."""
        locations = request.env['stock.location'].sudo().search([
            ('usage', '=', 'internal'),
            ('company_id', '=', request.env.company.id),
        ])
        return [{'id': loc.id, 'name': loc.complete_name} for loc in locations]

    @http.route('/my/loaner/checkout', type='jsonrpc', auth='user', website=True)
    def portal_loaner_checkout(self, **kw):
        """Checkout a loaner from the portal."""
        partner = request.env.user.partner_id
        if not partner.is_sales_rep_portal and not partner.is_authorizer:
            return {'error': 'Unauthorized'}

        product_id = int(kw.get('product_id', 0))
        lot_id = int(kw.get('lot_id', 0)) if kw.get('lot_id') else False
        sale_order_id = int(kw.get('sale_order_id', 0)) if kw.get('sale_order_id') else False
        client_id = int(kw.get('client_id', 0)) if kw.get('client_id') else False
        loaner_period = int(kw.get('loaner_period_days', 7))
        condition = kw.get('checkout_condition', 'good')
        notes = kw.get('checkout_notes', '')

        if not product_id:
            return {'error': 'Product is required'}

        vals = {
            'product_id': product_id,
            'loaner_period_days': loaner_period,
            'checkout_condition': condition,
            'checkout_notes': notes,
            'sales_rep_id': request.env.user.id,
        }
        if lot_id:
            vals['lot_id'] = lot_id
        if sale_order_id:
            so = request.env['sale.order'].sudo().browse(sale_order_id)
            if so.exists():
                vals['sale_order_id'] = so.id
                vals['partner_id'] = so.partner_id.id
                vals['authorizer_id'] = so.x_fc_authorizer_id.id if so.x_fc_authorizer_id else False
                vals['delivery_address'] = so.partner_shipping_id.contact_address if so.partner_shipping_id else ''
        if client_id and not vals.get('partner_id'):
            vals['partner_id'] = client_id

        if not vals.get('partner_id'):
            return {'error': 'Client is required'}

        try:
            checkout = request.env['fusion.loaner.checkout'].sudo().create(vals)
            checkout.action_checkout()
            return {
                'success': True,
                'checkout_id': checkout.id,
                'name': checkout.name,
                'message': f'Loaner {checkout.name} checked out successfully',
            }
        except Exception as e:
            _logger.error(f"Loaner checkout error: {e}")
            return {'error': str(e)}

    @http.route('/my/loaner/create-product', type='jsonrpc', auth='user', website=True)
    def portal_loaner_create_product(self, **kw):
        """Quick-create a loaner product with serial number from the portal."""
        partner = request.env.user.partner_id
        if not partner.is_sales_rep_portal and not partner.is_authorizer:
            return {'error': 'Unauthorized'}

        product_name = kw.get('product_name', '').strip()
        serial_number = kw.get('serial_number', '').strip()

        if not product_name:
            return {'error': 'Product name is required'}
        if not serial_number:
            return {'error': 'Serial number is required'}

        try:
            # Use provided category or default to Loaner Equipment
            category_id = kw.get('category_id')
            if category_id:
                category = request.env['product.category'].sudo().browse(int(category_id))
                if not category.exists():
                    category = None
            else:
                category = None

            if not category:
                category = request.env.ref('fusion_claims.product_category_loaner', raise_if_not_found=False)
            if not category:
                category = request.env['product.category'].sudo().search([
                    ('name', '=', 'Loaner Equipment'),
                ], limit=1)
            if not category:
                category = request.env['product.category'].sudo().create({
                    'name': 'Loaner Equipment',
                })

            # Create product template
            product_tmpl = request.env['product.template'].sudo().create({
                'name': product_name,
                'type': 'consu',
                'tracking': 'serial',
                'categ_id': category.id,
                'x_fc_can_be_loaned': True,
                'x_fc_loaner_period_days': 7,
                'sale_ok': False,
                'purchase_ok': False,
            })
            product = product_tmpl.product_variant_id

            # Create serial number (lot)
            lot = request.env['stock.lot'].sudo().create({
                'name': serial_number,
                'product_id': product.id,
                'company_id': request.env.company.id,
            })

            # Add stock in loaner location
            loaner_location = request.env.ref('fusion_claims.stock_location_loaner', raise_if_not_found=False)
            if loaner_location:
                request.env['stock.quant'].sudo().create({
                    'product_id': product.id,
                    'location_id': loaner_location.id,
                    'lot_id': lot.id,
                    'quantity': 1,
                })

            return {
                'success': True,
                'product_id': product.id,
                'product_name': product.name,
                'lot_id': lot.id,
                'lot_name': lot.name,
            }
        except Exception as e:
            _logger.error(f"Loaner product creation error: {e}")
            return {'error': str(e)}

    @http.route('/my/loaner/return', type='jsonrpc', auth='user', website=True)
    def portal_loaner_return(self, **kw):
        """Return/pickup a loaner from the portal."""
        partner = request.env.user.partner_id
        if not partner.is_sales_rep_portal and not partner.is_authorizer:
            return {'error': 'Unauthorized'}

        checkout_id = int(kw.get('checkout_id', 0))
        return_condition = kw.get('return_condition', 'good')
        return_notes = kw.get('return_notes', '')
        return_location_id = int(kw.get('return_location_id', 0)) if kw.get('return_location_id') else None

        if not checkout_id:
            return {'error': 'Checkout ID is required'}

        try:
            checkout = request.env['fusion.loaner.checkout'].sudo().browse(checkout_id)
            if not checkout.exists():
                return {'error': 'Checkout not found'}
            if checkout.state not in ('checked_out', 'overdue', 'rental_pending'):
                return {'error': 'This loaner is not currently checked out'}

            checkout.action_process_return(
                return_condition=return_condition,
                return_notes=return_notes,
                return_location_id=return_location_id,
            )
            return {
                'success': True,
                'message': f'Loaner {checkout.name} returned successfully',
            }
        except Exception as e:
            _logger.error(f"Loaner return error: {e}")
            return {'error': str(e)}

    # ==========================================================================
    # PUBLIC ASSESSMENT BOOKING
    # ==========================================================================

    @http.route('/book-assessment', type='http', auth='public', website=True, sitemap=True)
    def portal_book_assessment(self, **kw):
        """Public page for booking an accessibility assessment."""
        # Get available sales reps for assignment
        SalesGroup = request.env.ref('sales_team.group_sale_salesman', raise_if_not_found=False)
        sales_reps = []
        if SalesGroup:
            sales_reps = request.env['res.users'].sudo().search([
                ('groups_id', 'in', [SalesGroup.id]),
                ('active', '=', True),
            ])

        assessment_types = [
            ('stairlift_straight', 'Straight Stair Lift'),
            ('stairlift_curved', 'Curved Stair Lift'),
            ('vpl', 'Vertical Platform Lift'),
            ('ceiling_lift', 'Ceiling Lift'),
            ('ramp', 'Custom Ramp'),
            ('bathroom', 'Bathroom Modification'),
            ('tub_cutout', 'Tub Cutout'),
        ]

        values = {
            'assessment_types': assessment_types,
            'sales_reps': sales_reps,
            'success': kw.get('success'),
            'error': kw.get('error'),
        }
        return request.render('fusion_authorizer_portal.portal_book_assessment', values)

    @http.route('/book-assessment/submit', type='http', auth='public', website=True, methods=['POST'], csrf=True)
    def portal_book_assessment_submit(self, **kw):
        """Process assessment booking form submission."""
        try:
            # Validate required fields
            if not kw.get('client_name') or not kw.get('client_phone'):
                return request.redirect('/book-assessment?error=Please+provide+client+name+and+phone+number')

            if not kw.get('assessment_type'):
                return request.redirect('/book-assessment?error=Please+select+an+assessment+type')

            Assessment = request.env['fusion.accessibility.assessment'].sudo()

            # Determine booking source
            booking_source = 'portal'
            if kw.get('booking_source'):
                booking_source = kw['booking_source']

            # Parse date
            assessment_date = False
            if kw.get('assessment_date'):
                try:
                    assessment_date = fields.Date.from_string(kw['assessment_date'])
                except Exception:
                    assessment_date = False

            # Determine sales rep
            sales_rep_id = False
            if kw.get('sales_rep_id'):
                try:
                    sales_rep_id = int(kw['sales_rep_id'])
                except (ValueError, TypeError):
                    pass

            # Build address string
            address_parts = []
            if kw.get('client_street'):
                address_parts.append(kw['client_street'])
            if kw.get('client_city'):
                address_parts.append(kw['client_city'])
            if kw.get('client_province'):
                address_parts.append(kw['client_province'])
            if kw.get('client_postal'):
                address_parts.append(kw['client_postal'])

            vals = {
                'assessment_type': kw['assessment_type'],
                'client_name': kw['client_name'],
                'client_phone': kw.get('client_phone', ''),
                'client_email': kw.get('client_email', ''),
                'client_address': ', '.join(address_parts) if address_parts else '',
                'client_address_street': kw.get('client_street', ''),
                'client_address_city': kw.get('client_city', ''),
                'client_address_province': kw.get('client_province', ''),
                'client_address_postal': kw.get('client_postal', ''),
                'assessment_date': assessment_date,
                'booking_source': booking_source,
                'modification_requested': kw.get('modification_requested', ''),
            }

            if sales_rep_id:
                vals['sales_rep_id'] = sales_rep_id

            # Link authorizer if provided
            if kw.get('authorizer_name') and kw.get('authorizer_email'):
                Partner = request.env['res.partner'].sudo()
                authorizer = Partner.search([('email', '=', kw['authorizer_email'])], limit=1)
                if not authorizer:
                    authorizer = Partner.create({
                        'name': kw['authorizer_name'],
                        'email': kw['authorizer_email'],
                        'phone': kw.get('authorizer_phone', ''),
                        'is_authorizer': True,
                    })
                vals['authorizer_id'] = authorizer.id

            assessment = Assessment.create(vals)

            # Create calendar event for the sales rep
            if assessment_date and sales_rep_id:
                try:
                    from datetime import datetime as dt, timedelta
                    # Default: 10 AM, 1.5 hour duration
                    start = dt.combine(assessment_date, dt.min.time().replace(hour=10))
                    stop = start + timedelta(hours=1, minutes=30)
                    event = request.env['calendar.event'].sudo().create({
                        'name': f'Assessment: {kw["client_name"]} ({kw.get("client_city", "")})',
                        'start': fields.Datetime.to_string(start),
                        'stop': fields.Datetime.to_string(stop),
                        'user_id': sales_rep_id,
                        'location': vals.get('client_address', ''),
                        'description': (
                            f'Accessibility Assessment Booking\n'
                            f'Client: {kw["client_name"]}\n'
                            f'Phone: {kw.get("client_phone", "")}\n'
                            f'Type: {kw["assessment_type"]}\n'
                            f'Request: {kw.get("modification_requested", "")}'
                        ),
                        'partner_ids': [(4, request.env['res.users'].sudo().browse(sales_rep_id).partner_id.id)],
                    })
                    assessment.write({'calendar_event_id': event.id})
                except Exception as e:
                    _logger.error(f"Failed to create calendar event: {e}")

            # Send authorizer notification email
            if assessment.authorizer_id and assessment.authorizer_id.email:
                try:
                    company = request.env.company
                    body_html = assessment._email_build(
                        title='Assessment Scheduled',
                        summary=f'An accessibility assessment has been booked for '
                                f'<strong>{kw["client_name"]}</strong>.',
                        email_type='info',
                        sections=[('Booking Details', [
                            ('Client', kw['client_name']),
                            ('Phone', kw.get('client_phone', '')),
                            ('Address', vals.get('client_address', '')),
                            ('Assessment Type', dict(Assessment._fields['assessment_type'].selection).get(kw['assessment_type'], '')),
                            ('Date', str(assessment_date) if assessment_date else 'TBD'),
                            ('Requested', kw.get('modification_requested', '')),
                        ])],
                        note='This booking was made through the online portal.',
                        sender_name=company.name,
                    )
                    # Replace footer
                    body_html = body_html.replace(
                        'This is an automated notification from the ADP Claims Management System.',
                        'This is an automated notification from the Accessibility Case Management System.',
                    )
                    request.env['mail.mail'].sudo().create({
                        'subject': f'Assessment Booked - {kw["client_name"]}',
                        'body_html': body_html,
                        'email_to': assessment.authorizer_id.email,
                        'model': 'fusion.accessibility.assessment',
                        'res_id': assessment.id,
                    }).send()
                except Exception as e:
                    _logger.error(f"Failed to send authorizer notification: {e}")

            # Send Twilio SMS to client
            if kw.get('client_phone'):
                try:
                    ICP = request.env['ir.config_parameter'].sudo()
                    if ICP.get_param('fusion_claims.twilio_enabled', 'False').lower() in ('true', '1', 'yes'):
                        import requests as req
                        account_sid = ICP.get_param('fusion_claims.twilio_account_sid', '')
                        auth_token = ICP.get_param('fusion_claims.twilio_auth_token', '')
                        from_number = ICP.get_param('fusion_claims.twilio_phone_number', '')
                        company_phone = request.env.company.phone or ''
                        date_str = str(assessment_date) if assessment_date else 'a date to be confirmed'
                        sms_body = (
                            f"Hi {kw['client_name']}, your accessibility assessment with "
                            f"Westin Healthcare has been booked for {date_str}. "
                            f"For questions, call {company_phone}."
                        )
                        if all([account_sid, auth_token, from_number]):
                            url = f'https://api.twilio.com/2010-04-01/Accounts/{account_sid}/Messages.json'
                            req.post(url, data={
                                'To': kw['client_phone'],
                                'From': from_number,
                                'Body': sms_body,
                            }, auth=(account_sid, auth_token), timeout=10)
                            assessment.write({'sms_confirmation_sent': True})
                except Exception as e:
                    _logger.error(f"Failed to send SMS: {e}")

            return request.redirect('/book-assessment?success=1')

        except Exception as e:
            _logger.error(f"Assessment booking error: {e}")
            return request.redirect(f'/book-assessment?error={str(e)}')
