"""
Modelos de base de datos para Perfumados
Estructura mejorada con validaciones y relaciones
"""
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime, timedelta
import uuid

db = SQLAlchemy()


class Usuario(db.Model):
    """Usuarios del sistema con roles y permisos"""
    __tablename__ = 'usuario'

    id = db.Column(db.String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    nombre = db.Column(db.String(120), nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False, index=True)
    password_hash = db.Column(db.String(255), nullable=False)
    rol = db.Column(db.String(20), nullable=False, default='empleado')  # admin, supervisor, empleado
    local = db.Column(db.String(20), nullable=True)  # 'perfumados', 'copihue', 'perfumarte', o None (todos)
    activo = db.Column(db.Boolean, default=True, index=True)
    ultimo_acceso = db.Column(db.DateTime, nullable=True)
    creado = db.Column(db.DateTime, default=datetime.utcnow, index=True)
    actualizado = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    # Relaciones
    ventas = db.relationship('Venta', backref='registrado_por_user', lazy='dynamic')

    def set_password(self, password):
        """Hashea la contraseña"""
        self.password_hash = generate_password_hash(password)

    def check_password(self, password):
        """Verifica la contraseña"""
        return check_password_hash(self.password_hash, password)

    def tiene_permiso(self, modulo):
        """Valida permisos por rol"""
        permisos = {
            'admin': ['dashboard', 'ventas', 'reportes', 'empleados', 'asistencia', 'usuarios', 'cajas'],
            'supervisor': ['dashboard', 'ventas', 'reportes', 'empleados', 'asistencia', 'cajas'],
            'empleado': ['dashboard', 'asistencia']
        }
        return modulo in permisos.get(self.rol, [])

    def __repr__(self):
        return f'<Usuario {self.email}>'


class Empleado(db.Model):
    """Empleados registrados en el sistema"""
    __tablename__ = 'empleado'

    id = db.Column(db.String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    nombre = db.Column(db.String(120), nullable=False, index=True)
    rut = db.Column(db.String(20), unique=True, nullable=False, index=True)
    cargo = db.Column(db.String(50), nullable=False)
    local = db.Column(db.String(20), nullable=False, index=True)  # 'perfumados', 'copihue', 'perfumarte'
    telefono = db.Column(db.String(20), nullable=True)
    email = db.Column(db.String(120), nullable=True)
    salario_base = db.Column(db.Float, default=0)
    activo = db.Column(db.Boolean, default=True, index=True)
    creado = db.Column(db.DateTime, default=datetime.utcnow)
    actualizado = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    # Relaciones
    asistencias = db.relationship('Asistencia', backref='empleado', lazy='dynamic', cascade='all, delete-orphan')
    ventas = db.relationship('Venta', backref='vendedor_obj', lazy='dynamic')

    def __repr__(self):
        return f'<Empleado {self.nombre}>'


class Venta(db.Model):
    """Registro de ventas con detalles completos"""
    __tablename__ = 'venta'

    id = db.Column(db.String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    local = db.Column(db.String(20), nullable=False, index=True)
    fecha = db.Column(db.Date, nullable=False, index=True)
    producto = db.Column(db.String(255), nullable=False)
    cantidad = db.Column(db.Integer, nullable=False, default=1)
    precio_unitario = db.Column(db.Float, nullable=False)
    total = db.Column(db.Float, nullable=False)
    descuento = db.Column(db.Float, default=0)
    forma_pago = db.Column(db.String(20), nullable=False)  # efectivo, tarjeta, transferencia
    vendedor = db.Column(db.String(120), nullable=True)
    vendedor_id = db.Column(db.String(36), db.ForeignKey('empleado.id'), nullable=True)
    turno = db.Column(db.String(5), nullable=False)  # AM, PM
    registrado_por_id = db.Column(db.String(36), db.ForeignKey('usuario.id'), nullable=False, index=True)
    notas = db.Column(db.Text, nullable=True)
    creado = db.Column(db.DateTime, default=datetime.utcnow, index=True)

    def __repr__(self):
        return f'<Venta {self.local} {self.fecha} ${self.total}>'


class Asistencia(db.Model):
    """Control de asistencia con validación GPS"""
    __tablename__ = 'asistencia'

    id = db.Column(db.String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    empleado_id = db.Column(db.String(36), db.ForeignKey('empleado.id'), nullable=False, index=True)
    local = db.Column(db.String(20), nullable=False, index=True)
    fecha = db.Column(db.Date, nullable=False, index=True)
    entrada = db.Column(db.DateTime, nullable=True)
    salida = db.Column(db.DateTime, nullable=True)
    lat_entrada = db.Column(db.Float, nullable=True)
    lng_entrada = db.Column(db.Float, nullable=True)
    lat_salida = db.Column(db.Float, nullable=True)
    lng_salida = db.Column(db.Float, nullable=True)
    distancia_entrada = db.Column(db.Float, nullable=True)  # metros desde el local
    distancia_salida = db.Column(db.Float, nullable=True)
    valida = db.Column(db.Boolean, default=True)
    razon_invalida = db.Column(db.String(255), nullable=True)
    # Anti-fraude: fingerprint del dispositivo (userAgent + pantalla)
    device_fingerprint = db.Column(db.String(512), nullable=True)
    device_info = db.Column(db.String(255), nullable=True)  # descripción legible del dispositivo
    creado = db.Column(db.DateTime, default=datetime.utcnow)

    __table_args__ = (
        db.Index('idx_empleado_fecha', 'empleado_id', 'fecha'),
        db.Index('idx_local_fecha', 'local', 'fecha'),
    )

    def duracion_horas(self):
        """Calcula horas trabajadas"""
        if self.entrada and self.salida:
            delta = self.salida - self.entrada
            return delta.total_seconds() / 3600
        return 0

    def __repr__(self):
        return f'<Asistencia {self.empleado_id} {self.fecha}>'


class CajaDiaria(db.Model):
    """Cierre de caja por turno y local"""
    __tablename__ = 'caja_diaria'

    id = db.Column(db.String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    local = db.Column(db.String(20), nullable=False, index=True)
    fecha = db.Column(db.Date, nullable=False, index=True)
    turno = db.Column(db.String(5), nullable=False)  # AM, PM
    total_efectivo = db.Column(db.Float, default=0)
    total_tarjeta = db.Column(db.Float, default=0)
    total_transferencia = db.Column(db.Float, default=0)
    total_dia = db.Column(db.Float, default=0)
    diferencia = db.Column(db.Float, default=0)
    notas = db.Column(db.Text, nullable=True)
    cerrado = db.Column(db.Boolean, default=False)
    cerrado_por = db.Column(db.String(36), db.ForeignKey('usuario.id'), nullable=True)
    cerrado_en = db.Column(db.DateTime, nullable=True)
    creado = db.Column(db.DateTime, default=datetime.utcnow)

    __table_args__ = (
        db.UniqueConstraint('local', 'fecha', 'turno', name='uq_caja_local_fecha_turno'),
        db.Index('idx_local_fecha', 'local', 'fecha'),
    )

    def calcular_totales(self):
        """Calcula totales desde las ventas del día"""
        ventas = Venta.query.filter_by(
            local=self.local,
            fecha=self.fecha,
            turno=self.turno
        ).all()

        self.total_efectivo = sum(v.total for v in ventas if v.forma_pago == 'efectivo')
        self.total_tarjeta = sum(v.total for v in ventas if v.forma_pago == 'tarjeta')
        self.total_transferencia = sum(v.total for v in ventas if v.forma_pago == 'transferencia')
        self.total_dia = self.total_efectivo + self.total_tarjeta + self.total_transferencia

    def __repr__(self):
        return f'<CajaDiaria {self.local} {self.fecha} {self.turno}>'


class Producto(db.Model):
    """Catálogo de productos (opcional, para inventario futuro)"""
    __tablename__ = 'producto'

    id = db.Column(db.String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    nombre = db.Column(db.String(255), nullable=False, index=True)
    categoria = db.Column(db.String(100), nullable=True)
    sku = db.Column(db.String(50), unique=True, nullable=True, index=True)
    precio_base = db.Column(db.Float, nullable=False)
    stock = db.Column(db.Integer, default=0)
    activo = db.Column(db.Boolean, default=True, index=True)
    creado = db.Column(db.DateTime, default=datetime.utcnow)

    def __repr__(self):
        return f'<Producto {self.nombre}>'


# Configuración de marcas (agrupa los locales) — orden de aparición
MARCAS_CONFIG = {
    'perfumados': {'nombre': 'Perfumados',       'icono': '🌸', 'color': '#1a6b3c'},
    'perfumarte': {'nombre': 'Perfumarte',       'icono': '💐', 'color': '#7b4fa6'},
    'copihue':    {'nombre': 'Delicias Copihue', 'icono': '🌹', 'color': '#c62a2a'},
}

# Configuración de locales (cada local pertenece a una marca)
LOCALES_CONFIG = {
    # ── PERFUMADOS ──────────────────────────────────────────
    'perfumados_710': {
        'nombre': 'Perfumados Local 710',
        'marca':  'perfumados',
        'color':  '#1a6b3c',
        'icono':  '🌸',
        'lat': -36.7201, 'lng': -73.2478,
    },
    'perfumados_312': {
        'nombre': 'Perfumados Local 312',
        'marca':  'perfumados',
        'color':  '#1a6b3c',
        'icono':  '🌸',
        'lat': -36.7201, 'lng': -73.2478,
    },
    'perfumados_253': {
        'nombre': 'Perfumados Local 253',
        'marca':  'perfumados',
        'color':  '#1a6b3c',
        'icono':  '🌸',
        'lat': -36.7201, 'lng': -73.2478,
    },
    'perfumados_bodega1': {
        'nombre': 'Perfumados Bodega 1',
        'marca':  'perfumados',
        'color':  '#1a6b3c',
        'icono':  '🌸',
        'lat': -36.7201, 'lng': -73.2478,
    },
    'perfumados_bodega2': {
        'nombre': 'Perfumados Bodega 2',
        'marca':  'perfumados',
        'color':  '#1a6b3c',
        'icono':  '🌸',
        'lat': -36.7201, 'lng': -73.2478,
    },
    # ── PERFUMARTE (Concepción — 4 locales) ─────────────────
    'perfumarte_vega': {
        'nombre': 'Perfumarte Vega Monumental',
        'marca':  'perfumarte',
        'color':  '#7b4fa6',
        'icono':  '💐',
        'lat': -36.8282, 'lng': -73.0505,
    },
    'perfumarte_huellas': {
        'nombre': 'Perfumarte Huellas',
        'marca':  'perfumarte',
        'color':  '#7b4fa6',
        'icono':  '💐',
        'lat': -36.8270, 'lng': -73.0510,
    },
    'perfumarte_matriz': {
        'nombre': 'Perfumarte Casa Matriz',
        'marca':  'perfumarte',
        'color':  '#7b4fa6',
        'icono':  '💐',
        'lat': -36.8260, 'lng': -73.0498,
    },
    'perfumarte_barros': {
        'nombre': 'Perfumarte Barros Arana',
        'marca':  'perfumarte',
        'color':  '#7b4fa6',
        'icono':  '💐',
        'lat': -36.8275, 'lng': -73.0488,
    },
    # ── DELICIAS COPIHUE (1 sucursal) ───────────────────────
    'copihue': {
        'nombre': 'Delicias Copihue',
        'marca':  'copihue',
        'color':  '#c62a2a',
        'icono':  '🌹',
        'lat': -36.7205, 'lng': -73.2480,
    },
}
