from dataclasses import dataclass
from pydantic import BaseModel, field_validator, model_validator,Field
from typing import Any, Dict, List
from typing import Optional
from datetime import datetime 
from enum import Enum

from datetime import datetime, date
from decimal import Decimal

from src.constants import ChartTypeEnum,FinancialDashboardWidgetNameEnum,KPIWidgetNameEnum

class GlMasterData(BaseModel):
    general_ledger_code: int
    account_name: str
    category: str
    tags: List[str]

    @field_validator("tags", mode="before")
    @classmethod
    def normalize_tags(cls, tags: List[str]) -> List[str]:
        return [tag.strip().lower() for tag in tags]


class GeneralLedgerMasterDataRequest(BaseModel):
    data: List[GlMasterData]


class GeneralLedgerEntryUpdateRequest(BaseModel):
    date: Optional[datetime] = None
    general_ledger_code: Optional[float] = None
    account_name: Optional[str] = None
    category: Optional[str] = None
    description: Optional[str] = None
    debit: Optional[float] = None
    credit: Optional[float] = None
    extra_data: Optional[Dict[str, Any]]

    @model_validator(mode="after")
    def check_debit_or_credit(self) -> "GeneralLedgerEntryUpdateRequest":
        if self.debit is not None and self.credit is not None:
            raise ValueError("You can update either debit or credit, not both at the same time.")
        return self
    

class MetricDefinitionCreate(BaseModel):
    name: str
    tags: Optional[List[str]] = Field(default_factory=list)
    gl_codes: List[float] = Field(..., description="Required list of GL codes")
    amount_field: str = Field(..., description="Must be 'debit' or 'credit'")

    @field_validator("amount_field")
    def validate_amount_field(cls, v):
        if v not in {"debit", "credit"}:
            raise ValueError("amount_field must be 'debit' or 'credit'")
        return v


class DerivedMetricCreate(BaseModel):
    name: str
    formula: str


class OverviewWidgetSchema(BaseModel):
    year:int
    # name: FinancialDashboardWidgetNameEnum 
    name :str
    chart_Type: ChartTypeEnum
    enableordisable:bool
    position: int
class KPIWidgetSchema(BaseModel):
    name: KPIWidgetNameEnum
    chart_Type: ChartTypeEnum
    enableordisable:bool
    position: int
class WidgetSchema(BaseModel):
    name: str
    chart_Type: ChartTypeEnum
    enableordisable:bool
    position:int

@dataclass
class ReportParams:
    time_period: str
    custom_start: Optional[datetime]
    custom_end: Optional[datetime]
    year: Optional[int]
    period: str
    start_date: Optional[datetime]
    end_date: Optional[datetime]
    entity: Optional[str]
    hierarchy: Optional[str] 

class Filters(BaseModel):
    time_period :str 
    entity :str 
    department :str  

class TimeFilterEnum(str, Enum):
    all_periods = "all_periods"
    current_month = "current_month"
    last_month = "last_month"
    quarter_to_date = "quarter_to_date"
    year_to_date = "year_to_date" 


class ViewMoreFilter(str,Enum):
    # summery_view = "summery_view" 
    monthly_pl = "monthly_pl"
    quarterly_pl = "quarterly_pl" 
    actual_vs_budget = "actual_vs_budget"



class CashFlowViewMoreTimeFilters(str,Enum):
    quarterly = "quarterly"
    monthly = "monthly"
class CashFlowViewMoreViewFilters(str , Enum):
    summery_view = "summery_view" 
    detailed_view = "detailed_view"





    hierarchy: Optional[str]


class CustomerBase(BaseModel):
    customer_name: str
    industry: str
    region: Optional[str] = None
    revenue: float
    cost: float
    profit: float
    margin_pct: float
    refresh_timestamp: datetime

    class Config:
        from_attributes = True # Allows Pydantic to read from ORM models
#==============================================================================

class RevenueBase(BaseModel):
    product_name: str
    month: date
    revenue_amount: Decimal

class RevenueCreate(RevenueBase):
    pass

class RevenueResponse(RevenueBase):
    id: int

    class Config:
        orm_mode = True

class ScenarioFilter(str,Enum):
    actual  = "actual"
    budget  = "budget"
    forecast = "forecast"

#=====================================
class FCASchema(BaseModel):
    account_id: int
    account_code: int
    account_name:str
    account_type: str
    parent_account_id: str | None
    is_active : bool

    class Config:
        from_attributes = True # Allows Pydantic to read from ORM models

class GeneralLedgerTransactionSchema(BaseModel):
    transaction_id: int
    gl_account_id: str
    transaction_date: str
    amount_debit: float
    amount_credit: float
    currency: str
    department_id: str
    cost_center_id: Optional[str] = None
    profit_center_id: Optional[int] = None
    entity_id: Optional[int] = None
    customer_id: Optional[str] = None
    vendor_id: Optional[str] = None
    period: str
    class Config:
        from_attributes = True


class EntityBase(BaseModel):
    entity_id: str
    entity_name: str
    region: str
    currency: str
    class Config:
        from_attributes = True

    

class ProductQuarterly(BaseModel):
    product_name: Optional[str]
    customer_name: Optional[str]
    entity_name: str
    period_value: str
    region: str
    category: str
    q1: float
    q2: float
    q3: float
    q4: float
    total: float
    aiDriver: List[str]

class FiltersResponse(BaseModel):
    periods: List[str]
    entities: List[str]
    products: List[str]
    customers: List[str]
    regions: List[str]
    categories: List[str]

class SelectedFilters(BaseModel):
    period: str
    entity: Optional[str]
    product: Optional[str]
    customer: Optional[str]
    region: Optional[str]
    category: Optional[str]
    period_value: str

class RevenueKeyMetrics(BaseModel):
    total_revenue: float
    highest_product: Optional[str]
    lowest_product: Optional[str]
    growth_rate: float

class RevenueMetricsResponse(BaseModel):
    filters: FiltersResponse
    selected: SelectedFilters
    products: List[ProductQuarterly]
    key_metrics: RevenueKeyMetrics

class EntityOut(BaseModel):
    entity_id: str
    entity_name: str

    

class Project_Costing_KeyMetrics(BaseModel):
    total_budget: str
    total_actual: str
    total_variance: str
    on_budget_projects: int
    over_budget_projects: int


class EntityOut1(BaseModel):
    entity_id: str
    entity_name: str

class DepartmentOut1(BaseModel):
    department_id: str
    department_name: str


class ProductOut1(BaseModel):
    product_id: str
    product_name: str


class ProjectActual(BaseModel):
    entity_id: Optional[str]
    entity_name: Optional[str]
    region: Optional[str]
    department_id: Optional[str]
    department_name: Optional[str]
    product_id: Optional[str]
    product_name: Optional[str]
    vendor_name: Optional[str] = None
    category: Optional[str] = None 
    cost_center_id: str
    project_name: str
    is_active: Optional[bool]
    actual:str
    budget: str
    variance: str
    completion_percentage: float
    period: Optional[str]


# REQUIRED (names NOT changed)
class ProjectOut1(BaseModel):
    cost_center_id: str
    project_name: str


class RegionOut1(BaseModel):
    region: str

class VendorOut(BaseModel):
    vendor_id: str
    vendor_name: str


class ProjectCostingResponse(BaseModel):
    projects: List[dict]
    keymetrics: dict
    entities: List[EntityOut1]
    departments: Optional[List[DepartmentOut1]] = Field(default_factory=list)
    products: Optional[List[ProductOut1]] = Field(default_factory=list)
    projects_list: List[ProjectOut1]
    regions: List[RegionOut1]
    vendors: List[VendorOut]
    categories: List[str] 


# -----------------------------
# Key Metrics
# -----------------------------
class CustomerKeyMetrics(BaseModel):
    total_revenue: float
    total_cost: float
    total_profit: float
    profit_margin_pct: float

# -----------------------------
# Customer Output
# -----------------------------
class CustomerProfitabilityOut(BaseModel):
    customer_id: str
    customer_name: str
    entity_id: str
    entity_name: str
    entity_region: str  
    department_name: str
    product_name: str
    period: str
    year: int
    revenue: float
    cost: float
    profit: float
    margin_pct: float
    rank: str

# -----------------------------
# Entity Output
# -----------------------------
class EntityOut(BaseModel):
    entity_id: str
    entity_name: str
    region: Optional[str] = None

# -----------------------------
# Product Output (optional list)
# -----------------------------
class ProductOut(BaseModel):
    profit_center_id: str
    product_name: str

# -----------------------------
# Main Response
# -----------------------------
class CustomerSummaryResponse(BaseModel):
    keymetrics: CustomerKeyMetrics
    Customers: List[CustomerProfitabilityOut]
    entities: List[EntityOut]
    products: Optional[List[ProductOut]] = None  # optional list of all products
    regions: List[str] = []
    customers: List[dict] = []
    Year: int
    Period: str
    Selected_Entity: Optional[str] = None
    Selected_Customer: Optional[str] = None
    Selected_Product: Optional[str] = None
    Selected_Region: Optional[str] = None

class PayrollPeriodOption(str, Enum):
    all = "all"
    current_month = "current_month"
    last_month = "last_month"
    qtd = "qtd"
    ytd = "ytd"

class MonthlyBreakdown(BaseModel):
    period: str  # "Jan 2025"
    department: str
    entity: str
    region: str
    payroll: float
    benefits: float
    taxes: float
    total: float

class KeyMetrics(BaseModel):
    total_payroll: float
    total_benefits: float
    total_taxes: float
    grand_total: float
    average_per_month: float

class Filters(BaseModel):
    department: Optional[str] = None
    entity: Optional[str] = None
    region: Optional[str] = None

class PayrollReconciliationResponse1(BaseModel):
    year: int 
    period: PayrollPeriodOption
    filters: Filters
    keymetrics: KeyMetrics
    monthly_data: List[MonthlyBreakdown]
    departments: List[str]
    entities: List[str]
    regions: List[str]


class PayrollReconciliationRow(BaseModel):
    period: str
    gross_wages: Decimal
    taxes_withheld: Decimal
    benefits_deducted: Decimal
    net_pay_calculated: Decimal
    amount_disbursed: Decimal
    variance: Decimal


class PayrollReconciliationTotals(BaseModel):
    gross_wages: Decimal
    taxes_withheld: Decimal
    benefits_deducted: Decimal
    net_pay_calculated: Decimal
    amount_disbursed: Decimal
    variance: Decimal


class PayrollReconciliationResponse(BaseModel):
    year: int
    totals: PayrollReconciliationTotals
    data: List[PayrollReconciliationRow]

class ScenarioFilter(str,Enum):
    actual  = "actual"
    budget  = "budget"
    forecast = "forecast" 

class CurrencyFilter(str,Enum):
    thousands = "thousands"
    millions  = "millions"
    actual_value = "actualvalue"

class FunnelStage(BaseModel):
    stage: str
    count: int
    conversion_rate: float
    region: Optional[str]
    product_name: Optional[str]

class Funnel_KeyMetrics(BaseModel):
    total_leads: int
    total_won: int
    overall_conversion: float
    average_sales_cycle_days: float

class CRMFunnelResponse(BaseModel):
    year: int
    period: str
    key_metrics: dict
    funnel: List[FunnelStage]
    regions: List[str]
    products: List[str]

class DashboardTimeFilter(str, Enum):
    monthly = "monthly"
    quarterly = "quarterly"
    year_to_date = "year_to_date"  

class ComparityFilter(str, Enum):
    month_on_month = "month_on_month"
    year_on_year = "year_on_year"

class KPIWidgetUpdateSchema(BaseModel):
    name: KPIWidgetNameEnum
    chart_Type: Optional[ChartTypeEnum] = None
    enableordisable: Optional[bool] = None
    position: Optional[int] = None 
class BudgetFilter(str, Enum):
    budget_data = "budget_data",
    # budget_opex = "budget_opex",
    # budget_cogs = "budget_cogs",


