use serde::{Deserialize, Serialize};

/// Store path for the persisted portfolio ledger.
pub const PORTFOLIO_LEDGER_STORE_PATH: &str = "portfolio-ledger.json";
/// Top-level key used inside the Tauri store.
pub const PORTFOLIO_LEDGER_KEY: &str = "ledger";
/// Current persisted schema version.
pub const PORTFOLIO_SCHEMA_VERSION: u32 = 1;
/// Base currency supported by the local portfolio backend.
pub const DEFAULT_BASE_CURRENCY: &str = "USD";

/// Persisted portfolio ledger containing the transaction source of truth.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PortfolioLedger {
    pub schema_version: u32,
    pub base_currency: String,
    pub transactions: Vec<PortfolioTransaction>,
}

impl Default for PortfolioLedger {
    fn default() -> Self {
        Self {
            schema_version: PORTFOLIO_SCHEMA_VERSION,
            base_currency: DEFAULT_BASE_CURRENCY.to_string(),
            transactions: Vec::new(),
        }
    }
}

/// Supported portfolio transaction kinds.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub enum TransactionKind {
    Buy,
    Sell,
    CashDeposit,
    CashWithdrawal,
}

impl TransactionKind {
    #[must_use]
    pub const fn as_label(&self) -> &'static str {
        match self {
            Self::Buy => "BUY",
            Self::Sell => "SELL",
            Self::CashDeposit => "CASH_DEPOSIT",
            Self::CashWithdrawal => "CASH_WITHDRAWAL",
        }
    }
}

/// Persisted transaction record.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PortfolioTransaction {
    pub id: String,
    pub kind: TransactionKind,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub symbol: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub company_name: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub quantity: Option<f64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub price: Option<f64>,
    pub gross_amount: f64,
    pub fee: f64,
    pub executed_at: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub note: Option<String>,
}

/// Open FIFO lot tracked during replay.
#[derive(Debug, Clone, PartialEq)]
pub struct OpenLot {
    pub quantity: f64,
    pub price: f64,
}

/// Replay-derived position state before live quote enrichment.
#[derive(Debug, Clone, PartialEq)]
pub struct PositionSnapshot {
    pub symbol: String,
    pub company_name: String,
    pub quantity: f64,
    pub cost_basis: f64,
    pub open_lots: Vec<OpenLot>,
    pub latest_trade_at: Option<String>,
    pub latest_trade_price: Option<f64>,
}

/// Replay-derived snapshot for the entire ledger.
#[derive(Debug, Clone, PartialEq)]
pub struct ReplaySnapshot {
    pub cash_balance: f64,
    pub realized_gain: f64,
    pub positions: Vec<PositionSnapshot>,
}

/// Live-priced holding row returned to command consumers.
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct PortfolioHolding {
    pub symbol: String,
    pub name: String,
    pub quantity: f64,
    pub cost_basis: f64,
    pub current_price: f64,
    pub current_value: f64,
    pub unrealized_gain: f64,
    pub gain_loss_percent: f64,
    pub latest_trade_at: Option<String>,
    pub stale_pricing: bool,
    pub day_change: f64,
}

/// Portfolio valuation and summary stats after live price enrichment.
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct PortfolioSnapshot {
    pub holdings: Vec<PortfolioHolding>,
    pub cash_balance: f64,
    pub invested_cost_basis: f64,
    pub equities_market_value: f64,
    pub total_portfolio_value: f64,
    pub realized_gain: f64,
    pub unrealized_gain: f64,
    pub day_change: f64,
    pub day_change_percent: f64,
    pub stale_pricing_symbols: Vec<String>,
}

/// Summary values rendered by `/portfolio stats`.
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct PortfolioStats {
    pub cash_balance: f64,
    pub holdings_count: usize,
    pub invested_cost_basis: f64,
    pub equities_market_value: f64,
    pub total_portfolio_value: f64,
    pub realized_gain: f64,
    pub unrealized_gain: f64,
    pub day_change: f64,
    pub stale_pricing_symbols: Vec<String>,
}

/// Confirmation payload returned after a trade command succeeds.
#[derive(Debug, Clone, PartialEq)]
pub struct TradeConfirmation {
    pub symbol: String,
    pub company_name: String,
    pub quantity: f64,
    pub price: f64,
    pub gross_amount: f64,
    pub cash_balance: f64,
    pub realized_gain: Option<f64>,
}

/// Confirmation payload returned after a cash command succeeds.
#[derive(Debug, Clone, PartialEq)]
pub struct CashConfirmation {
    pub amount: f64,
    pub cash_balance: f64,
    pub kind: TransactionKind,
}
