"""
scrylo/db/models.py
--------------------
SQLAlchemy ORM models. SQLite backing store at ~/.scrylo/scrylo.db.
All lead data, campaign history, and open tracking stays local — no cloud.
"""

from __future__ import annotations

from datetime import datetime
from enum import Enum as PyEnum

from sqlalchemy import (
    Boolean,
    DateTime,
    Enum,
    Float,
    ForeignKey,
    Integer,
    String,
    Text,
    create_engine,
    func,
)
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship

from scrylo.core.config import DB_PATH


# ── Base ──────────────────────────────────────────────────────────────────
class Base(DeclarativeBase):
    pass


# ── Enums ─────────────────────────────────────────────────────────────────
class LeadStatus(str, PyEnum):
    NEW = "new"
    ENRICHED = "enriched"
    PITCHED = "pitched"
    SENT = "sent"
    OPENED = "opened"
    REPLIED = "replied"
    UNSUBSCRIBED = "unsubscribed"
    BOUNCED = "bounced"


class EmailEventType(str, PyEnum):
    SENT = "sent"
    OPENED = "opened"
    CLICKED = "clicked"
    BOUNCED = "bounced"
    REPLIED = "replied"


# ── Models ────────────────────────────────────────────────────────────────
class Lead(Base):
    """
    Core lead record. Created by scraper, enriched by NLP pipeline,
    pitched by LLM, sent by email engine.
    """
    __tablename__ = "leads"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=func.now())
    updated_at: Mapped[datetime] = mapped_column(DateTime, default=func.now(), onupdate=func.now())

    # ── Identity ──────────────────────────────────────────────────────────
    full_name: Mapped[str | None] = mapped_column(String(200))
    first_name: Mapped[str | None] = mapped_column(String(100))
    last_name: Mapped[str | None] = mapped_column(String(100))
    role: Mapped[str | None] = mapped_column(String(200))
    company: Mapped[str | None] = mapped_column(String(200))
    location: Mapped[str | None] = mapped_column(String(200))
    website: Mapped[str | None] = mapped_column(String(500))
    linkedin_url: Mapped[str | None] = mapped_column(String(500))
    industry: Mapped[str | None] = mapped_column(String(200))

    # ── Contact ───────────────────────────────────────────────────────────
    email: Mapped[str | None] = mapped_column(String(300))
    email_confidence: Mapped[float | None] = mapped_column(Float)   # 0.0 – 1.0
    email_verified: Mapped[bool] = mapped_column(Boolean, default=False)

    # ── Enrichment (NLP — Week 5) ─────────────────────────────────────────
    pain_points: Mapped[str | None] = mapped_column(Text)           # JSON list
    icp_score: Mapped[float | None] = mapped_column(Float)          # 0.0 – 100.0
    company_summary: Mapped[str | None] = mapped_column(Text)
    news_hook: Mapped[str | None] = mapped_column(Text)

    # ── Pitch (LLM — Week 6) ──────────────────────────────────────────────
    pitch_subject: Mapped[str | None] = mapped_column(String(500))
    pitch_body: Mapped[str | None] = mapped_column(Text)
    pitch_generated_by: Mapped[str | None] = mapped_column(String(50))  # "llm" | "template"

    # ── Status & source ───────────────────────────────────────────────────
    status: Mapped[str] = mapped_column(String(50), default=LeadStatus.NEW)
    source: Mapped[str | None] = mapped_column(String(100))         # primary source
    sources: Mapped[str | None] = mapped_column(Text)               # JSON list: ["ddg","crunchbase","gh"]
    contact_method: Mapped[str | None] = mapped_column(String(50))  # "email" | "linkedin_dm"
    raw_data: Mapped[str | None] = mapped_column(Text)              # original scraped JSON

    # ── Extra profiles ────────────────────────────────────────────────────
    github_url: Mapped[str | None] = mapped_column(String(500))
    twitter_url: Mapped[str | None] = mapped_column(String(500))
    phone: Mapped[str | None] = mapped_column(String(100))

    # ── Relationships ─────────────────────────────────────────────────────
    email_events: Mapped[list[EmailEvent]] = relationship(
        "EmailEvent", back_populates="lead", cascade="all, delete-orphan"
    )

    def __repr__(self) -> str:
        return f"<Lead {self.id} {self.full_name} @ {self.company}>"


class EmailCampaign(Base):
    """
    A named batch of emails. Groups sends for reporting.
    """
    __tablename__ = "email_campaigns"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=func.now())

    name: Mapped[str] = mapped_column(String(300))
    description: Mapped[str | None] = mapped_column(Text)
    total_sent: Mapped[int] = mapped_column(Integer, default=0)
    total_opened: Mapped[int] = mapped_column(Integer, default=0)
    total_replied: Mapped[int] = mapped_column(Integer, default=0)
    total_bounced: Mapped[int] = mapped_column(Integer, default=0)

    events: Mapped[list[EmailEvent]] = relationship(
        "EmailEvent", back_populates="campaign", cascade="all, delete-orphan"
    )

    @property
    def open_rate(self) -> float:
        if self.total_sent == 0:
            return 0.0
        return round(self.total_opened / self.total_sent * 100, 1)

    def __repr__(self) -> str:
        return f"<Campaign {self.id} '{self.name}' sent={self.total_sent}>"


class EmailEvent(Base):
    """
    Individual email event — sent, opened, clicked, bounced, replied.
    Tracking pixel fires an OPENED event when the lead opens the email.
    """
    __tablename__ = "email_events"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    occurred_at: Mapped[datetime] = mapped_column(DateTime, default=func.now())

    lead_id: Mapped[int] = mapped_column(Integer, ForeignKey("leads.id"))
    campaign_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("email_campaigns.id"))
    event_type: Mapped[str] = mapped_column(String(50))             # EmailEventType
    event_meta: Mapped[str | None] = mapped_column(Text)           # JSON — IP, user-agent etc.

    lead: Mapped[Lead] = relationship("Lead", back_populates="email_events")
    campaign: Mapped[EmailCampaign | None] = relationship("EmailCampaign", back_populates="events")

    def __repr__(self) -> str:
        return f"<EmailEvent {self.event_type} lead={self.lead_id}>"


class Unsubscribe(Base):
    """
    CAN-SPAM / GDPR compliance — built in from day one (not as afterthought).
    Any email in this table is permanently excluded from all future sends.
    """
    __tablename__ = "unsubscribes"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    unsubscribed_at: Mapped[datetime] = mapped_column(DateTime, default=func.now())
    email: Mapped[str] = mapped_column(String(300), unique=True, index=True)
    reason: Mapped[str | None] = mapped_column(String(200))         # "user_request" | "bounce" etc.

    def __repr__(self) -> str:
        return f"<Unsubscribe {self.email}>"
