from sqlalchemy import Column, String, Integer, Float, DateTime, ForeignKey, Enum, Text, JSON, UniqueConstraint, Boolean
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from app.database import db
import enum

class UserRole(str, enum.Enum):
    SUPER_ADMIN = "super-admin"
    BUSINESS_ADMIN = "business-admin"
    CUSTOMER = "customer"

class BusinessApplicationStatus(str, enum.Enum):
    PENDING = "pending"
    APPROVED = "approved"
    REJECTED = "rejected"
    NONE = "none"

class TireType(str, enum.Enum):
    """Enum para tipos de llanta (mantenido para compatibilidad con columna antigua)."""
    HIGHWAY = "Pista / Carretera (H/T)"
    ALL_TERRAIN = "Uso Mixto (A/T)"
    MUD_TERRAIN = "Todo Terreno (M/T)"
    ULTRA_HIGH_PERFORMANCE = "Deportiva (UHP)"

# Tablas normalizadas para llantas
class TipoLlanta(db.Model):
    """Tabla normalizada para tipos de llanta."""
    __tablename__ = "tipos_llanta"
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    nombre = Column("nombre", String(100), unique=True, nullable=False, index=True)
    descripcion = Column("descripcion", Text, nullable=True)
    creado_en = Column("creado_en", DateTime(timezone=True), server_default=func.now())
    
    # Relationships
    llantas = relationship("Tire", back_populates="tipo_llanta_rel")
    
    def __repr__(self):
        return f"<TipoLlanta {self.nombre}>"

class MarcaLlanta(db.Model):
    """Tabla normalizada para marcas de llanta."""
    __tablename__ = "marcas_llanta"
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    nombre = Column("nombre", String(100), unique=True, nullable=False, index=True)
    pais_origen = Column("pais_origen", String(100), nullable=True)
    creado_en = Column("creado_en", DateTime(timezone=True), server_default=func.now())
    
    # Relationships
    llantas = relationship("Tire", back_populates="marca_llanta_rel")
    modelos = relationship("ModeloLlanta", back_populates="marca", cascade="all, delete-orphan")
    
    def __repr__(self):
        return f"<MarcaLlanta {self.nombre}>"

class ModeloLlanta(db.Model):
    """Tabla normalizada para modelos de llanta."""
    __tablename__ = "modelos_llanta"
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    marca_id = Column("marca_id", Integer, ForeignKey("marcas_llanta.id"), nullable=False, index=True)
    nombre = Column("nombre", String(255), nullable=False)
    descripcion = Column("descripcion", Text, nullable=True)
    creado_en = Column("creado_en", DateTime(timezone=True), server_default=func.now())
    
    # Relationships
    marca = relationship("MarcaLlanta", back_populates="modelos")
    llantas = relationship("Tire", back_populates="modelo_llanta_rel")
    
    # Unique constraint: una marca no puede tener dos modelos con el mismo nombre
    __table_args__ = (
        UniqueConstraint('marca_id', 'nombre', name='uq_marca_modelo'),
        {"mysql_engine": "InnoDB"},
    )
    
    def __repr__(self):
        return f"<ModeloLlanta {self.nombre}>"

class User(db.Model):
    __tablename__ = "usuarios"
    
    id = Column(String(255), primary_key=True, index=True)
    email = Column(String(255), unique=True, index=True, nullable=False)
    password_hash = Column(String(255), nullable=False)
    rol = Column("rol", Enum(UserRole, values_callable=lambda x: [e.value for e in x]), nullable=False, default=UserRole.CUSTOMER)
    negocio_id = Column("negocio_id", String(255), ForeignKey("negocios_llantas.id"), nullable=True)
    estado_solicitud_negocio = Column(
        "estado_solicitud_negocio",
        Enum(BusinessApplicationStatus, values_callable=lambda x: [e.value for e in x]), 
        nullable=True, 
        default=BusinessApplicationStatus.NONE
    )
    creado_en = Column("creado_en", DateTime(timezone=True), server_default=func.now())
    actualizado_en = Column("actualizado_en", DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
    
    # Relationships
    business = relationship("TireBusiness", back_populates="admins")
    
    # Aliases para compatibilidad con código existente
    @property
    def role(self):
        return self.rol
    
    @role.setter
    def role(self, value):
        self.rol = value
    
    @property
    def business_id(self):
        return self.negocio_id
    
    @business_id.setter
    def business_id(self, value):
        self.negocio_id = value
    
    @property
    def business_application_status(self):
        return self.estado_solicitud_negocio
    
    @business_application_status.setter
    def business_application_status(self, value):
        self.estado_solicitud_negocio = value
    
    @property
    def created_at(self):
        return self.creado_en
    
    @property
    def updated_at(self):
        return self.actualizado_en

class Tire(db.Model):
    __tablename__ = "llantas"
    
    id = Column(String(255), primary_key=True, index=True)
    # Foreign keys a tablas normalizadas (nullable temporalmente para migración)
    marca_id = Column("marca_id", Integer, ForeignKey("marcas_llanta.id"), nullable=True, index=True)
    modelo_id = Column("modelo_id", Integer, ForeignKey("modelos_llanta.id"), nullable=True, index=True)
    tipo_id = Column("tipo_id", Integer, ForeignKey("tipos_llanta.id"), nullable=True, index=True)
    # Columnas antiguas (mantenidas para compatibilidad durante migración)
    marca = Column("marca", String(255), nullable=True, index=True)
    modelo = Column("modelo", String(255), nullable=True)
    tipo = Column("tipo", Enum(TireType, values_callable=lambda x: [e.value for e in x]), nullable=True)
    # Tamaño de la llanta
    ancho = Column("ancho", Integer, nullable=False)
    relacion_aspecto = Column("relacion_aspecto", Integer, nullable=False)
    diametro = Column("diametro", Integer, nullable=False)
    # Imagen
    url_imagen = Column("url_imagen", Text, nullable=True)
    # Timestamps
    creado_en = Column("creado_en", DateTime(timezone=True), server_default=func.now())
    actualizado_en = Column("actualizado_en", DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
    
    # Relationships
    marca_llanta_rel = relationship("MarcaLlanta", back_populates="llantas")
    modelo_llanta_rel = relationship("ModeloLlanta", back_populates="llantas")
    tipo_llanta_rel = relationship("TipoLlanta", back_populates="llantas")
    inventory_items = relationship("InventoryItem", back_populates="tire")
    
    # Aliases para compatibilidad con código existente
    @property
    def brand(self):
        # Priorizar relación normalizada, luego columna antigua
        if self.marca_llanta_rel:
            return self.marca_llanta_rel.nombre
        elif self.marca:
            return self.marca
        return ""
    
    @brand.setter
    def brand(self, value):
        # Este setter busca o crea la marca y actualiza ambas columnas
        if isinstance(value, str):
            # Actualizar columna antigua para compatibilidad
            self.marca = value
            # Buscar o crear en tabla normalizada
            marca = MarcaLlanta.query.filter_by(nombre=value).first()
            if marca:
                self.marca_id = marca.id
            else:
                # Si no existe, crear una nueva
                nueva_marca = MarcaLlanta(nombre=value)
                db.session.add(nueva_marca)
                db.session.flush()
                self.marca_id = nueva_marca.id
    
    @property
    def model(self):
        # Priorizar relación normalizada, luego columna antigua
        if self.modelo_llanta_rel:
            return self.modelo_llanta_rel.nombre
        elif self.modelo:
            return self.modelo
        return ""
    
    @model.setter
    def model(self, value):
        # Este setter busca o crea el modelo y actualiza ambas columnas
        if isinstance(value, str):
            # Actualizar columna antigua para compatibilidad
            self.modelo = value
            # Buscar o crear en tabla normalizada
            if self.marca_id:
                modelo = ModeloLlanta.query.filter_by(marca_id=self.marca_id, nombre=value).first()
                if modelo:
                    self.modelo_id = modelo.id
                else:
                    # Si no existe, crear uno nuevo
                    nuevo_modelo = ModeloLlanta(marca_id=self.marca_id, nombre=value)
                    db.session.add(nuevo_modelo)
                    db.session.flush()
                    self.modelo_id = nuevo_modelo.id
    
    @property
    def width(self):
        return self.ancho
    
    @width.setter
    def width(self, value):
        self.ancho = value
    
    @property
    def aspect_ratio(self):
        return self.relacion_aspecto
    
    @aspect_ratio.setter
    def aspect_ratio(self, value):
        self.relacion_aspecto = value
    
    @property
    def diameter(self):
        return self.diametro
    
    @diameter.setter
    def diameter(self, value):
        self.diametro = value
    
    @property
    def type(self):
        """Retorna el nombre del tipo de llanta"""
        # Priorizar relación normalizada, luego columna antigua/Enum
        if self.tipo_llanta_rel:
            return self.tipo_llanta_rel.nombre
        elif self.tipo:
            # Si es Enum, obtener su valor
            if isinstance(self.tipo, TireType):
                return self.tipo.value
            elif isinstance(self.tipo, str):
                return self.tipo
        return ""
    
    @type.setter
    def type(self, value):
        """Setter para tipo - busca o crea el tipo y actualiza ambas columnas"""
        if isinstance(value, str):
            # Actualizar columna antigua para compatibilidad
            try:
                self.tipo = TireType(value)
            except ValueError:
                # Si no es un valor válido del Enum, guardar como string
                self.tipo = value
            # Buscar o crear en tabla normalizada
            tipo = TipoLlanta.query.filter_by(nombre=value).first()
            if tipo:
                self.tipo_id = tipo.id
            else:
                # Si no existe, crear uno nuevo
                nuevo_tipo = TipoLlanta(nombre=value)
                db.session.add(nuevo_tipo)
                db.session.flush()
                self.tipo_id = nuevo_tipo.id
        elif isinstance(value, TipoLlanta):
            self.tipo_id = value.id
            # Actualizar columna antigua también
            self.tipo = value.nombre
        elif isinstance(value, TireType):
            self.tipo = value
            # Buscar en tabla normalizada
            tipo = TipoLlanta.query.filter_by(nombre=value.value).first()
            if tipo:
                self.tipo_id = tipo.id
    
    @property
    def image_url(self):
        return self.url_imagen
    
    @image_url.setter
    def image_url(self, value):
        self.url_imagen = value
    
    @property
    def created_at(self):
        return self.creado_en
    
    @property
    def updated_at(self):
        return self.actualizado_en

class TireBusiness(db.Model):
    __tablename__ = "negocios_llantas"
    
    id = Column(String(255), primary_key=True, index=True)
    nombre = Column("nombre", String(255), nullable=False)
    direccion = Column("direccion", Text, nullable=False)
    telefono = Column("telefono", String(50), nullable=False)
    email = Column(String(255), nullable=False)
    horarios = Column("horarios", String(255), nullable=False)
    calificacion = Column("calificacion", Float, default=0.0, nullable=False)
    cantidad_resenas = Column("cantidad_resenas", Integer, default=0, nullable=False)
    descripcion = Column("descripcion", Text, nullable=True)
    url_mapa_google = Column("url_mapa_google", Text, nullable=True)
    url_imagen = Column("url_imagen", Text, nullable=True)
    redes_sociales = Column("redes_sociales", JSON, nullable=True)  # Store as JSON: {facebook, instagram, tiktok, whatsapp}
    creado_en = Column("creado_en", DateTime(timezone=True), server_default=func.now())
    actualizado_en = Column("actualizado_en", DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
    
    # Relationships
    admins = relationship("User", back_populates="business")
    inventory_items = relationship("InventoryItem", back_populates="business")
    
    # Aliases para compatibilidad con código existente
    @property
    def name(self):
        return self.nombre
    
    @name.setter
    def name(self, value):
        self.nombre = value
    
    @property
    def address(self):
        return self.direccion
    
    @address.setter
    def address(self, value):
        self.direccion = value
    
    @property
    def phone(self):
        return self.telefono
    
    @phone.setter
    def phone(self, value):
        self.telefono = value
    
    @property
    def hours(self):
        return self.horarios
    
    @hours.setter
    def hours(self, value):
        self.horarios = value
    
    @property
    def rating(self):
        return self.calificacion
    
    @rating.setter
    def rating(self, value):
        self.calificacion = value
    
    @property
    def review_count(self):
        return self.cantidad_resenas
    
    @review_count.setter
    def review_count(self, value):
        self.cantidad_resenas = value
    
    @property
    def description(self):
        return self.descripcion
    
    @description.setter
    def description(self, value):
        self.descripcion = value
    
    @property
    def google_maps_embed_url(self):
        return self.url_mapa_google
    
    @google_maps_embed_url.setter
    def google_maps_embed_url(self, value):
        self.url_mapa_google = value
    
    @property
    def image_url(self):
        return self.url_imagen
    
    @image_url.setter
    def image_url(self, value):
        self.url_imagen = value
    
    @property
    def socials(self):
        return self.redes_sociales
    
    @socials.setter
    def socials(self, value):
        self.redes_sociales = value
    
    @property
    def created_at(self):
        return self.creado_en
    
    @property
    def updated_at(self):
        return self.actualizado_en

class InventoryItem(db.Model):
    __tablename__ = "items_inventario"
    
    id = Column(String(255), primary_key=True, index=True)
    negocio_id = Column("negocio_id", String(255), ForeignKey("negocios_llantas.id"), nullable=False, index=True)
    llanta_id = Column("llanta_id", String(255), ForeignKey("llantas.id"), nullable=False, index=True)
    cantidad = Column("cantidad", Integer, nullable=False, default=0)
    precio = Column("precio", Float, nullable=False)  # Price in PEN
    creado_en = Column("creado_en", DateTime(timezone=True), server_default=func.now())
    actualizado_en = Column("actualizado_en", DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
    
    # Relationships
    business = relationship("TireBusiness", back_populates="inventory_items")
    tire = relationship("Tire", back_populates="inventory_items")
    
    # Unique constraint on negocio_id + llanta_id
    __table_args__ = (
        UniqueConstraint('negocio_id', 'llanta_id', name='uq_negocio_llanta'),
        {"mysql_engine": "InnoDB"},
    )
    
    # Aliases para compatibilidad con código existente
    @property
    def business_id(self):
        return self.negocio_id
    
    @business_id.setter
    def business_id(self, value):
        self.negocio_id = value
    
    @property
    def tire_id(self):
        return self.llanta_id
    
    @tire_id.setter
    def tire_id(self, value):
        self.llanta_id = value
    
    @property
    def quantity(self):
        return self.cantidad
    
    @quantity.setter
    def quantity(self, value):
        self.cantidad = value
    
    @property
    def price(self):
        return self.precio
    
    @price.setter
    def price(self, value):
        self.precio = value
    
    @property
    def created_at(self):
        return self.creado_en
    
    @property
    def updated_at(self):
        return self.actualizado_en

class Review(db.Model):
    __tablename__ = "resenas"
    
    id = Column(String(255), primary_key=True, index=True)
    negocio_id = Column("negocio_id", String(255), ForeignKey("negocios_llantas.id"), nullable=False, index=True)
    usuario_id = Column("usuario_id", String(255), ForeignKey("usuarios.id"), nullable=False, index=True)
    # Campos normalizados: nombre_usuario y avatar_usuario deberían venir de usuarios
    # Pero los mantenemos por compatibilidad con datos existentes
    nombre_usuario = Column("nombre_usuario", String(255), nullable=True)  # Puede ser NULL si viene de usuario
    avatar_usuario = Column("avatar_usuario", Text, nullable=True)  # Puede ser NULL si viene de usuario
    calificacion = Column("calificacion", Integer, nullable=False)  # 1-5
    comentario = Column("comentario", Text, nullable=True)
    creado_en = Column("creado_en", DateTime(timezone=True), server_default=func.now())
    
    # Relationships
    business = relationship("TireBusiness")
    user = relationship("User")
    
    # Aliases para compatibilidad con código existente
    @property
    def business_id(self):
        return self.negocio_id
    
    @business_id.setter
    def business_id(self, value):
        self.negocio_id = value
    
    @property
    def user_id(self):
        return self.usuario_id
    
    @user_id.setter
    def user_id(self, value):
        self.usuario_id = value
    
    @property
    def user_name(self):
        return self.nombre_usuario
    
    @user_name.setter
    def user_name(self, value):
        self.nombre_usuario = value
    
    @property
    def user_avatar(self):
        return self.avatar_usuario
    
    @user_avatar.setter
    def user_avatar(self, value):
        self.avatar_usuario = value
    
    @property
    def rating(self):
        return self.calificacion
    
    @rating.setter
    def rating(self, value):
        self.calificacion = value
    
    @property
    def comment(self):
        return self.comentario
    
    @comment.setter
    def comment(self, value):
        self.comentario = value

class PasswordResetToken(db.Model):
    __tablename__ = "tokens_recuperacion"
    
    id = Column(String(255), primary_key=True, index=True)
    usuario_id = Column("usuario_id", String(255), ForeignKey("usuarios.id"), nullable=False, index=True)
    token = Column("token", String(191), nullable=False, unique=True, index=True)  # 191 para evitar problemas con índices únicos en MySQL
    expira_en = Column("expira_en", DateTime(timezone=True), nullable=False)
    usado = Column("usado", Boolean, default=False, nullable=False)
    creado_en = Column("creado_en", DateTime(timezone=True), server_default=func.now())
    
    # Relationships
    user = relationship("User")
    
    @property
    def user_id(self):
        return self.usuario_id
    
    @user_id.setter
    def user_id(self, value):
        self.usuario_id = value
    
    @property
    def expires_at(self):
        return self.expira_en
    
    @expires_at.setter
    def expires_at(self, value):
        self.expira_en = value
    
    @property
    def used(self):
        return self.usado
    
    @used.setter
    def used(self, value):
        self.usado = value
    
    @property
    def created_at(self):
        return self.creado_en

