from datetime import datetime
from typing import List, Optional
from sqlalchemy import Integer, String, Boolean, Float, DateTime, ForeignKey, Text, JSON
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.db.database import Base

# -----------------
# 1. System & Config
# -----------------

class AiConfig(Base):
    __tablename__ = "ai_configs"

    id: Mapped[str] = mapped_column(String, primary_key=True)
    name: Mapped[str] = mapped_column(String)
    providerType: Mapped[str] = mapped_column(String) # Gemini, Ollama, OpenAI
    modelName: Mapped[str] = mapped_column(String)
    baseUrl: Mapped[Optional[str]] = mapped_column(String, nullable=True)

class ApiSettings(Base):
    __tablename__ = "api_settings"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, default=1) # Always 1
    
    # Credentials
    appKey: Mapped[Optional[str]] = mapped_column(String, nullable=True)
    appSecret: Mapped[Optional[str]] = mapped_column(String, nullable=True)
    accountNumber: Mapped[Optional[str]] = mapped_column(String, nullable=True)
    
    # Integrations
    useTelegram: Mapped[bool] = mapped_column(Boolean, default=False)
    telegramToken: Mapped[Optional[str]] = mapped_column(String, nullable=True)
    telegramChatId: Mapped[Optional[str]] = mapped_column(String, nullable=True)
    
    useNaverNews: Mapped[bool] = mapped_column(Boolean, default=False)
    naverClientId: Mapped[Optional[str]] = mapped_column(String, nullable=True)
    naverClientSecret: Mapped[Optional[str]] = mapped_column(String, nullable=True)
    
    # Configs
    kisApiDelayMs: Mapped[int] = mapped_column(Integer, default=250)
    newsScrapIntervalMin: Mapped[int] = mapped_column(Integer, default=10)
    
    # Token Storage (Runtime)
    accessToken: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    tokenExpiry: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
    websocketApprovalKey: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    
    # AI Config Relations (Foreign Keys)
    preferredNewsAiId: Mapped[Optional[str]] = mapped_column(ForeignKey("ai_configs.id"), nullable=True)
    preferredStockAiId: Mapped[Optional[str]] = mapped_column(ForeignKey("ai_configs.id"), nullable=True)
    preferredNewsJudgementAiId: Mapped[Optional[str]] = mapped_column(ForeignKey("ai_configs.id"), nullable=True)
    preferredAutoBuyAiId: Mapped[Optional[str]] = mapped_column(ForeignKey("ai_configs.id"), nullable=True)
    preferredAutoSellAiId: Mapped[Optional[str]] = mapped_column(ForeignKey("ai_configs.id"), nullable=True)

# -----------------
# 2. Account & Portfolio
# -----------------

class AccountStatus(Base):
    __tablename__ = "account_status"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, default=1)
    totalAssets: Mapped[float] = mapped_column(Float, default=0.0)
    buyingPower: Mapped[float] = mapped_column(Float, default=0.0)
    dailyProfit: Mapped[float] = mapped_column(Float, default=0.0)
    dailyProfitRate: Mapped[float] = mapped_column(Float, default=0.0)

class Holding(Base):
    __tablename__ = "holdings"

    stockCode: Mapped[str] = mapped_column(String, primary_key=True)
    stockName: Mapped[str] = mapped_column(String)
    quantity: Mapped[int] = mapped_column(Integer)
    avgPrice: Mapped[float] = mapped_column(Float)
    currentPrice: Mapped[float] = mapped_column(Float) # Real-time updated
    profit: Mapped[float] = mapped_column(Float)
    profitRate: Mapped[float] = mapped_column(Float)
    marketValue: Mapped[float] = mapped_column(Float)

# -----------------
# 3. Market & Discovery
# -----------------

class MasterStock(Base):
    __tablename__ = "master_stocks"

    code: Mapped[str] = mapped_column(String, primary_key=True)
    name: Mapped[str] = mapped_column(String)
    market: Mapped[str] = mapped_column(String) # Domestic, Overseas
    
    # Stats
    per: Mapped[float] = mapped_column(Float, default=0.0)
    pbr: Mapped[float] = mapped_column(Float, default=0.0)
    roe: Mapped[float] = mapped_column(Float, default=0.0)
    marketCap: Mapped[float] = mapped_column(Float, default=0.0)
    dividendYield: Mapped[float] = mapped_column(Float, default=0.0)
    
    # User Data
    memo: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    isHidden: Mapped[bool] = mapped_column(Boolean, default=False)

class NewsCache(Base):
    __tablename__ = "news_cache"

    news_id: Mapped[str] = mapped_column(String, primary_key=True) # Hashed ID
    title: Mapped[str] = mapped_column(Text)
    description: Mapped[str] = mapped_column(Text)
    link: Mapped[str] = mapped_column(Text)
    pubDate: Mapped[str] = mapped_column(String)
    
    sentiment: Mapped[Optional[str]] = mapped_column(String, nullable=True)
    relatedThemes: Mapped[Optional[List]] = mapped_column(JSON, nullable=True)
    relatedStocks: Mapped[Optional[List]] = mapped_column(JSON, nullable=True)

class DiscoveryRankingCache(Base):
    __tablename__ = "discovery_ranking_cache"
    
    # Composite Key simulated (category_market string or separate cols)
    # Using composite PK
    category: Mapped[str] = mapped_column(String, primary_key=True)
    market: Mapped[str] = mapped_column(String, primary_key=True)
    
    updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
    items_json: Mapped[str] = mapped_column(Text) # JSON String of StockItem[]

class StockStat(Base):
    __tablename__ = "stock_stats"

    code: Mapped[str] = mapped_column(String, primary_key=True)
    tradingValue: Mapped[float] = mapped_column(Float, default=0.0)
    
    buyRatio: Mapped[int] = mapped_column(Integer, default=0)
    sellRatio: Mapped[int] = mapped_column(Integer, default=0)
    foreignNetBuy: Mapped[int] = mapped_column(Integer, default=0)
    institutionalNetBuy: Mapped[int] = mapped_column(Integer, default=0)
    
    aiScoreBuy: Mapped[int] = mapped_column(Integer, default=0)
    aiScoreSell: Mapped[int] = mapped_column(Integer, default=0)

# -----------------
# 4. Watchlist
# -----------------

class WatchlistGroup(Base):
    __tablename__ = "watchlist_groups"

    id: Mapped[str] = mapped_column(String, primary_key=True)
    name: Mapped[str] = mapped_column(String)
    market: Mapped[str] = mapped_column(String) # Domestic, Overseas

class WatchlistItem(Base):
    __tablename__ = "watchlist_items"

    group_id: Mapped[str] = mapped_column(ForeignKey("watchlist_groups.id"), primary_key=True)
    stock_code: Mapped[str] = mapped_column(String, primary_key=True)
    added_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)

# -----------------
# 5. Trading & Automation
# -----------------

class TradeHistory(Base):
    __tablename__ = "trade_history"

    id: Mapped[str] = mapped_column(String, primary_key=True)
    stockCode: Mapped[str] = mapped_column(String)
    stockName: Mapped[str] = mapped_column(String)
    type: Mapped[str] = mapped_column(String) # BUY, SELL
    
    quantity: Mapped[int] = mapped_column(Integer)
    price: Mapped[float] = mapped_column(Float)
    
    timestamp: Mapped[datetime] = mapped_column(DateTime)
    status: Mapped[str] = mapped_column(String) # FILLED, CANCELLED

class AutoTradeRobot(Base):
    __tablename__ = "auto_trade_robots"

    id: Mapped[str] = mapped_column(String, primary_key=True)
    stockCode: Mapped[str] = mapped_column(String)
    stockName: Mapped[str] = mapped_column(String)
    groupId: Mapped[Optional[str]] = mapped_column(String, nullable=True)
    
    type: Mapped[str] = mapped_column(String) # ACCUMULATION, TRAILING, etc.
    frequency: Mapped[str] = mapped_column(String) # DAILY, WEEKLY
    executionTime: Mapped[str] = mapped_column(String) # HH:MM
    market: Mapped[str] = mapped_column(String)
    
    quantity: Mapped[int] = mapped_column(Integer)
    specificDay: Mapped[Optional[int]] = mapped_column(Integer, nullable=True) # 0=Monday
    trailingPercent: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    
    active: Mapped[bool] = mapped_column(Boolean, default=True)

class ReservedOrder(Base):
    __tablename__ = "reserved_orders"

    id: Mapped[str] = mapped_column(String, primary_key=True)
    stockCode: Mapped[str] = mapped_column(String)
    stockName: Mapped[str] = mapped_column(String)
    type: Mapped[str] = mapped_column(String) # BUY, SELL
    market: Mapped[str] = mapped_column(String)
    
    monitoringType: Mapped[str] = mapped_column(String) # TARGET, TRAILING
    trailingType: Mapped[Optional[str]] = mapped_column(String, nullable=True) # AMOUNT, PERCENT
    status: Mapped[str] = mapped_column(String) # MONITORING, TRIGGERED, EXPIRED
    
    quantity: Mapped[int] = mapped_column(Integer)
    
    triggerPrice: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    trailingValue: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    stopLossValue: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    
    highestPrice: Mapped[Optional[float]] = mapped_column(Float, nullable=True) # For Trailing
    lowestPrice: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    
    useStopLoss: Mapped[bool] = mapped_column(Boolean, default=False)
    sellAll: Mapped[bool] = mapped_column(Boolean, default=False)
    stopLossType: Mapped[Optional[str]] = mapped_column(String, nullable=True)
    
    createdAt: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
    expiryDate: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
