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

from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
from datetime import datetime, timedelta


class SkeenServicio(models.Model):
    _name = 'skeen.servicio'
    _description = 'Servicio Dermatológico'
    _order = 'sequence, name'
    
    name = fields.Char(string='Nombre', required=True)
    code = fields.Char(string='Código', required=True, copy=False)
    description = fields.Text(string='Descripción')
    
    # Precio y duración
    price = fields.Float(string='Precio', required=True, default=0.0)
    duration_min = fields.Integer(string='Duración (min)', required=True, default=30)
    
    # Precio por paquete (Opción B)
    package_price = fields.Float(string='Precio Paquete', default=0.0)
    package_sessions = fields.Integer(string='Sesiones en Paquete', default=0)
    package_notes = fields.Char(string='Notas del Paquete')
    
    # Categoría
    category = fields.Selection([
        ('consulta', 'Consulta'),
        ('tratamiento', 'Tratamiento'),
        ('procedimiento', 'Procedimiento'),
        ('paquete', 'Paquete'),
    ], string='Categoría', default='tratamiento', required=True)
    
    # Visual / agrupación
    color = fields.Char(string='Color', default='#1abc9c')
    service_group = fields.Char(string='Grupo')
    is_favorite = fields.Boolean(string='Favorito', default=False)
    genera_monedero = fields.Boolean(string='Genera monedero', default=True,
                                     help='Si está activo, la venta de este servicio acumula puntos monedero.')
    tag_ids = fields.Many2many('skeen.service.tag', string='Etiquetas')
    
    # Configuración
    active = fields.Boolean(string='Activo', default=True)
    sequence = fields.Integer(string='Secuencia', default=10)
    
    # Relaciones
    cita_ids = fields.One2many('skeen.cita', 'servicio_id', string='Citas')
    
    _sql_constraints = [
        ('unique_code', 'unique(code)', 'El código debe ser único!')
    ]


class SkeenServiceTag(models.Model):
    _name = 'skeen.service.tag'
    _description = 'Etiqueta de Servicio'
    
    name = fields.Char(string='Nombre', required=True)
    color = fields.Integer(string='Color')
    service_ids = fields.Many2many('skeen.servicio', string='Servicios')


class SkeenCita(models.Model):
    _name = 'skeen.cita'
    _description = 'Cita Médica'
    _order = 'date, time'
    _inherit = ['mail.thread', 'mail.activity.mixin']
    
    # Identificación
    name = fields.Char(string='Referencia', readonly=True, copy=False)
    
    # Paciente
    partner_id = fields.Many2one('res.partner', string='Paciente', required=True,
                                  domain=[('is_patient', '=', True)])
    partner_phone = fields.Char(related='partner_id.phone', string='Teléfono', readonly=True)
    partner_email = fields.Char(related='partner_id.email', string='Email', readonly=True)
    
    # Servicio
    servicio_id = fields.Many2one('skeen.servicio', string='Servicio', required=True)
    servicio_price = fields.Float(related='servicio_id.price', string='Precio Servicio', readonly=True)
    servicio_duration = fields.Integer(related='servicio_id.duration_min', string='Duración', readonly=True)
    
    # Fecha y hora
    date = fields.Date(string='Fecha', required=True, index=True)
    time = fields.Float(string='Hora', required=True)
    time_str = fields.Char(string='Hora Texto', compute='_compute_time_str', store=True)
    datetime_start = fields.Datetime(string='Inicio', compute='_compute_datetime', store=True)
    datetime_end = fields.Datetime(string='Fin', compute='_compute_datetime', store=True)
    
    # Ubicación y médico
    branch = fields.Selection([
        ('rosarito', 'Rosarito'),
        ('tijuana', 'Tijuana'),
    ], string='Sucursal', default='rosarito')
    doctor_id = fields.Many2one('hr.employee', string='Médico / Especialista')
    medium = fields.Selection([
        ('videocall', 'Videollamada'),
        ('onsite', 'Presencial'),
    ], string='Medio', default='onsite')
    
    # Estado de flujo del sistema original
    flow_state = fields.Selection([
        ('preconsulta', 'Pre-consulta'),
        ('link_sent', 'Link enviado'),
        ('approval', 'Aprobación'),
        ('assign_record', 'Asignar expediente'),
        ('scheduled', 'Agendar'),
    ], string='Estado de Flujo', default='scheduled')
    
    # Estado
    state = fields.Selection([
        ('pending', 'Pendiente'),
        ('confirmed', 'Confirmada'),
        ('arrived', 'Llegó'),
        ('in_progress', 'En Progreso'),
        ('done', 'Completada'),
        ('cancelled', 'Cancelada'),
        ('no_show', 'No Show'),
    ], string='Estado', default='pending', tracking=True)
    
    # Notas
    notes = fields.Text(string='Notas')
    cancellation_reason = fields.Text(string='Motivo Cancelación')
    
    # Recordatorio
    reminder_sent = fields.Boolean(string='Recordatorio Enviado', default=False)
    reminder_date = fields.Datetime(string='Fecha Recordatorio')
    
    # Pago
    payment_state = fields.Selection([
        ('not_paid', 'No Pagado'),
        ('partial', 'Parcial'),
        ('paid', 'Pagado'),
    ], string='Estado de Pago', default='not_paid')
    amount_paid = fields.Float(string='Monto Pagado', default=0.0)
    
    # WACRM
    wacrm_conversation_id = fields.Char(string='WACRM Conversation ID')

    # Paquete terminado (para servicios con categoría 'paquete')
    package_finished = fields.Boolean(string='Paquete Terminado', default=False)
    package_finished_date = fields.Datetime(string='Fecha Término Paquete')
    
    @api.depends('date', 'time', 'servicio_id')
    def _compute_datetime(self):
        for cita in self:
            if cita.date and cita.time is not False:
                hours = int(cita.time)
                minutes = int((cita.time - hours) * 60)
                cita.datetime_start = datetime.combine(cita.date, datetime.min.time().replace(hour=hours, minute=minutes))
                if cita.servicio_id:
                    cita.datetime_end = cita.datetime_start + timedelta(minutes=cita.servicio_id.duration_min)
                else:
                    cita.datetime_end = cita.datetime_start + timedelta(minutes=30)

    @api.depends('time')
    def _compute_time_str(self):
        for cita in self:
            if cita.time is not False:
                hours = int(cita.time)
                minutes = int((cita.time - hours) * 60)
                cita.time_str = f"{hours:02d}:{minutes:02d}"
            else:
                cita.time_str = ""
    
    @api.model_create_multi
    def create(self, vals_list):
        for vals in vals_list:
            if not vals.get('name'):
                vals['name'] = self.env['ir.sequence'].next_by_code('skeen.cita') or 'CITA-001'
        return super(SkeenCita, self).create(vals_list)
    
    def action_confirm(self):
        self.write({'state': 'confirmed'})
    
    def action_arrive(self):
        self.write({'state': 'arrived'})
    
    def action_start(self):
        self.write({'state': 'in_progress'})
    
    def action_done(self):
        self.write({'state': 'done'})
        # Actualizar última visita del paciente
        self.partner_id.write({'last_visit': fields.Date.today()})
    
    def action_cancel(self):
        return {
            'type': 'ir.actions.act_window',
            'name': 'Cancelar Cita',
            'res_model': 'skeen.cita.cancel.wizard',
            'view_mode': 'form',
            'target': 'new',
            'context': {'default_cita_id': self.id}
        }
    
    def action_no_show(self):
        self.write({'state': 'no_show'})

    def action_package_finished(self):
        """Marca la cita como paquete terminado (servicios de categoría 'paquete').

        Reversible: se puede desmarcar escribiendo package_finished=False.
        También deja la cita en 'done' y actualiza la última visita del paciente.
        """
        for cita in self:
            vals = {
                'package_finished': True,
                'package_finished_date': fields.Datetime.now(),
            }
            if cita.state not in ('done', 'cancelled', 'no_show'):
                vals['state'] = 'done'
            cita.write(vals)
            if cita.partner_id:
                cita.partner_id.write({'last_visit': fields.Date.today()})
        return True
    
    def action_send_reminder(self):
        self.write({'reminder_sent': True, 'reminder_date': fields.Datetime.now()})
    
    @api.constrains('date', 'time', 'servicio_id')
    def _check_availability(self):
        for cita in self:
            if cita.state in ('cancelled', 'no_show'):
                continue
            # Verificar solapamiento
            domain = [
                ('id', '!=', cita.id),
                ('date', '=', cita.date),
                ('state', 'not in', ('cancelled', 'no_show')),
                ('datetime_start', '<', cita.datetime_end),
                ('datetime_end', '>', cita.datetime_start),
            ]
            overlapping = self.search(domain)
            if overlapping:
                raise ValidationError(_('Ya existe una cita en ese horario!'))

    @api.constrains('date', 'time', 'doctor_id', 'servicio_id')
    def _check_bloqueos(self):
        """Rechaza citas que se solapan con un bloqueo de agenda del médico"""
        for cita in self:
            if cita.state in ('cancelled', 'no_show') or not cita.doctor_id or not cita.date:
                continue
            dur = ((cita.servicio_id.duration_min if cita.servicio_id else 30) or 30) / 60.0
            ini = cita.time
            fin = ini + dur
            bloqueos = self.env['skeen.cita.bloqueo'].search([
                ('doctor_id', '=', cita.doctor_id.id),
                ('date', '=', cita.date),
            ])
            for b in bloqueos:
                if b.all_day or (ini < b.time_to and fin > b.time_from):
                    raise ValidationError(_('El médico tiene un bloqueo (%s)') % (b.motivo or 'agenda bloqueada'))
    
    def get_available_slots(self, date, servicio_id):
        """Retorna slots disponibles para una fecha y servicio"""
        servicio = self.env['skeen.servicio'].browse(servicio_id)
        duration = servicio.duration_min if servicio else 30
        
        # Horario de la clínica
        start_time = 9.0  # 9:00 AM
        end_time = 18.0   # 6:00 PM
        
        # Generar slots
        slots = []
        current = start_time
        while current + (duration / 60.0) <= end_time:
            # Verificar si está ocupado
            slot_start = datetime.combine(date, datetime.min.time().replace(hour=int(current), minute=int((current % 1) * 60)))
            slot_end = slot_start + timedelta(minutes=duration)
            
            domain = [
                ('date', '=', date),
                ('state', 'not in', ('cancelled', 'no_show')),
                ('datetime_start', '<', slot_end),
                ('datetime_end', '>', slot_start),
            ]
            if not self.search(domain):
                slots.append({
                    'time': current,
                    'time_str': f"{int(current):02d}:{int((current % 1) * 60):02d}",
                })
            current += 0.5  # Slots cada 30 min
        
        return slots
