"""Database models."""
from datetime import datetime, date

from sqlalchemy import (
    JSON,
    Date,
    DateTime,
    Float,
    ForeignKey,
    Integer,
    String,
    Text,
)
from sqlalchemy.orm import Mapped, mapped_column, relationship

from .database import Base


class User(Base):
    __tablename__ = "users"

    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    email: Mapped[str] = mapped_column(String(255), unique=True, index=True)
    password_hash: Mapped[str] = mapped_column(String(255))
    role: Mapped[str] = mapped_column(String(8), default="user")  # admin | user
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)


class ScanRun(Base):
    __tablename__ = "scan_runs"

    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    started_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
    universe_size: Mapped[int] = mapped_column(Integer, default=0)
    candidates: Mapped[int] = mapped_column(Integer, default=0)
    signals_created: Mapped[int] = mapped_column(Integer, default=0)
    results: Mapped[list] = mapped_column(JSON, default=list)  # scanner rows


class Signal(Base):
    __tablename__ = "signals"

    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    scan_run_id: Mapped[int | None] = mapped_column(ForeignKey("scan_runs.id"), nullable=True)
    symbol: Mapped[str] = mapped_column(String(12), index=True)
    company: Mapped[str] = mapped_column(String(120), default="")
    direction: Mapped[str] = mapped_column(String(4))  # CALL | PUT | BUY | SELL
    signal_type: Mapped[str] = mapped_column(String(8), default="options", index=True)  # options | swing
    status: Mapped[str] = mapped_column(String(12), index=True)  # approved | rejected
    risk_rating: Mapped[str] = mapped_column(String(8), default="medium")  # low|medium|high

    price: Mapped[float] = mapped_column(Float, default=0)
    confidence: Mapped[float] = mapped_column(Float, default=0)     # 0-100
    probability: Mapped[float] = mapped_column(Float, default=0)    # 0-100

    entry: Mapped[float] = mapped_column(Float, default=0)
    stop_loss: Mapped[float] = mapped_column(Float, default=0)
    target1: Mapped[float] = mapped_column(Float, default=0)
    target2: Mapped[float] = mapped_column(Float, default=0)
    risk_reward: Mapped[float] = mapped_column(Float, default=0)
    position_size: Mapped[int] = mapped_column(Integer, default=0)  # shares
    max_risk_usd: Mapped[float] = mapped_column(Float, default=0)

    scores: Mapped[dict] = mapped_column(JSON, default=dict)        # per-agent scores
    rationale: Mapped[list] = mapped_column(JSON, default=list)     # list[str]
    rejection_reasons: Mapped[list] = mapped_column(JSON, default=list)
    option_contract: Mapped[dict] = mapped_column(JSON, default=dict)
    indicators: Mapped[dict] = mapped_column(JSON, default=dict)
    history: Mapped[list] = mapped_column(JSON, default=list)       # recent closes for charting

    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, index=True)

    trades = relationship("PaperTrade", back_populates="signal")


class PaperTrade(Base):
    __tablename__ = "paper_trades"

    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    signal_id: Mapped[int | None] = mapped_column(ForeignKey("signals.id"), nullable=True)
    symbol: Mapped[str] = mapped_column(String(12), index=True)
    direction: Mapped[str] = mapped_column(String(4))
    quantity: Mapped[int] = mapped_column(Integer, default=0)
    entry_price: Mapped[float] = mapped_column(Float, default=0)
    stop_loss: Mapped[float] = mapped_column(Float, default=0)
    initial_stop: Mapped[float | None] = mapped_column(Float, nullable=True)  # original stop for R math
    scaled_out: Mapped[int] = mapped_column(Integer, default=0)  # 0/1: half already banked
    target: Mapped[float] = mapped_column(Float, default=0)
    status: Mapped[str] = mapped_column(String(8), default="open", index=True)  # open|closed

    # Option position simulation (contract selected by the Options Agent)
    instrument: Mapped[str] = mapped_column(String(8), default="shares")  # shares|option
    option_contract: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    option_entry_premium: Mapped[float | None] = mapped_column(Float, nullable=True)
    option_last_premium: Mapped[float | None] = mapped_column(Float, nullable=True)
    option_contracts: Mapped[int] = mapped_column(Integer, default=0)
    option_pnl: Mapped[float] = mapped_column(Float, default=0)

    exit_price: Mapped[float | None] = mapped_column(Float, nullable=True)
    exit_reason: Mapped[str | None] = mapped_column(String(32), nullable=True)
    pnl: Mapped[float] = mapped_column(Float, default=0)
    last_price: Mapped[float] = mapped_column(Float, default=0)
    # Prediction audit: excursions in R-multiples (max favorable / adverse)
    mfe_r: Mapped[float] = mapped_column(Float, default=0)
    mae_r: Mapped[float] = mapped_column(Float, default=0)
    opened_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
    closed_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)

    signal = relationship("Signal", back_populates="trades")


class AlertLog(Base):
    """Tracks sent alerts to dedupe per (symbol, direction, day)."""

    __tablename__ = "alert_log"

    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    symbol: Mapped[str] = mapped_column(String(12), index=True)
    direction: Mapped[str] = mapped_column(String(4))
    alert_date: Mapped[date] = mapped_column(Date, index=True)
    kind: Mapped[str] = mapped_column(String(16), default="signal")  # signal | trade_close
    signal_id: Mapped[int | None] = mapped_column(ForeignKey("signals.id"), nullable=True)
    sent_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)


class DailyReport(Base):
    __tablename__ = "daily_reports"

    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    report_date: Mapped[date] = mapped_column(Date, unique=True, index=True)
    summary: Mapped[str] = mapped_column(Text, default="")
    payload: Mapped[dict] = mapped_column(JSON, default=dict)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
