# src/database/models.py
from datetime import datetime
from sqlalchemy import (
    Column, Integer, String, DateTime, ForeignKey,
    Enum as SAEnum, JSON, Index, Text
)
from sqlalchemy.orm import declarative_base, relationship, backref

from .enums import (
    Gender, PracticePlace, ClientsExperience,
    MassageTechnique, SocialSkill, CommunicationEase, DayStatus, StrategyStatus, FailReason
)

Base = declarative_base()

# Helper to keep portable (no PG ENUM), store as VARCHAR+CHECK
def portable_enum(py_enum):
    """Return non-native SQLAlchemy Enum that stores values as VARCHAR with CHECK constraint."""
    return SAEnum(
        py_enum,
        native_enum=False,              # <-- critical: no PG ENUM type
        create_constraint=True,         # emit CHECK constraint
        validate_strings=True,          # validate input strings
        values_callable=lambda e: [m.value for m in e],  # store enum.value
    )

# ───────────────────────── USERS ─────────────────────────

class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True)
    tg_id = Column(String(64), unique=True, nullable=False)
    user_name = Column(String(128))
    # Portable enum (stored as VARCHAR + CHECK)
    user_gender = Column(portable_enum(Gender), nullable=True)
    city = Column(String(128))

    # Timestamps
    created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
    updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)

    # One-to-one profile
    profile = relationship(
        "UserProfile",
        uselist=False,
        back_populates="user",
        cascade="all, delete-orphan"
    )
    


class UserProfile(Base):
    __tablename__ = "user_profile"

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), unique=True, nullable=False)

    # Portable enums
    where_practicing   = Column(portable_enum(PracticePlace),   nullable=True)
    have_clients       = Column(portable_enum(ClientsExperience), nullable=True)
    massage_technique  = Column(portable_enum(MassageTechnique), nullable=True)
    social_skill       = Column(portable_enum(SocialSkill),       nullable=True)
    communication_ease = Column(portable_enum(CommunicationEase), nullable=True)

    # Portable JSON
    raw_json = Column(JSON, nullable=True)

    updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)

    user = relationship("User", back_populates="profile")


# ───────────────────────── BOT SETTINGS ─────────────────────────
class BotSettings(Base):
    __tablename__ = "bot_settings"

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), unique=True, nullable=False)
    
    # Bot personality settings
    bot_voice_name = Column(String(128), nullable=True)  # Имя бота (например, "Анна", "Алексей")
    bot_voice_gender = Column(portable_enum(Gender), nullable=True)  # Пол бота для обращений
    
    # Timestamps
    created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
    updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
    
    user = relationship("User", backref=backref("bot_settings", uselist=False), passive_deletes=True)

# ───────────────────────── STRATEGY ─────────────────────────
class Strategy(Base):
    __tablename__ = "strategies"

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)

    # Full, human-readable plan (HTML/markdown/text) that explains the overall approach
    strategy = Column(Text, nullable=False)

    # Steps map by day: {"1": {"html": "..."},"2": {"html": "..."} , ...}
    # Keep it as the "ideal path"; do NOT mutate on progress — only regenerate when logic requires.
    steps = Column(JSON, nullable=False)

    # Minimal lifecycle
    status = Column(portable_enum(StrategyStatus), nullable=False, default=StrategyStatus.active)

    # Cursor for current logical day in the plan
    current_day = Column(Integer, nullable=False, default=1)

    user = relationship("User", backref="strategies", passive_deletes=True)

    __table_args__ = (
        Index("ix_strategies_user_status", "user_id", "status"),
    )

# ───────────────────────── PER-DAY STATE ─────────────────────────
class StrategyDayState(Base):
    __tablename__ = "strategy_day_state"

    id = Column(Integer, primary_key=True)
    strategy_id = Column(Integer, ForeignKey("strategies.id", ondelete="CASCADE"), nullable=False)

    # Day number from Strategy.steps (string keys "1","2",...) — store as int
    day_number = Column(Integer, nullable=False)

    # Status machine for the day
    status = Column(portable_enum(DayStatus), nullable=False, default=DayStatus.planned)
    fail_reason = Column(portable_enum(FailReason), nullable=True)

    # When snoozed, plan your APScheduler to ping again
    snooze_until = Column(DateTime(timezone=True), nullable=True)

    strategy = relationship("Strategy", backref="day_states", passive_deletes=True)

    __table_args__ = (
        Index("ix_day_state_strategy_day", "strategy_id", "day_number"),
    )
