from typing import Optional, TypedDict, Union, Dict, List
from pydantic import BaseModel, root_validator, Field
from datetime import datetime, timedelta, date
from fastapi import Query
from enum import Enum

class PuTest(BaseModel):
    data_arr: list

class WatchlistAPI(BaseModel):
    symbol: str
    exchange: str
    action: int

class IndexAPI(BaseModel):
    symbol: Optional[str] = None
    exchange: Optional[str] = None

class GraphDataInput(BaseModel):
    symbol: str
    exchange: str
    new_close: Optional[float] = None
    offset: Optional[str] = Field(default="3")
    duration: Optional[str] = Field(default="1M")

class ModelInput(BaseModel):
    symbol: str
    exchange: str
    time_range: Optional[str] = Field(default="1W")
    start_date: Optional[str] = None
    end_date: Optional[str] = None

class AnalyzeMultipleRequest(BaseModel):
    instrument: str
    duration: Optional[str] = Field(default="1Y")
    exchange: Optional[str] = Field(default="NSE")
    length: int = Query(100, ge=1, description="Number of items per page")
    offset: int = Query(0, ge=0, description="Offset to start fetching data")

class PortfolioReportGet(BaseModel):
    investor: str
    data_type: int
    start_date: Optional[str] = None
    end_date: Optional[str] = None

    @root_validator(pre=True)
    def set_default_dates(cls, values):
        if values.get("start_date") is None and values.get("end_date") is None:
            end_date = datetime.today()
            start_date = end_date - timedelta(days=30)
            values["start_date"] = start_date.strftime("%Y-%m-%d")
            values["end_date"] = end_date.strftime("%Y-%m-%d")
        return values

class PortfolioCreate(BaseModel):
    investor: str
    description: Optional[str] = None

class UnitOrder(BaseModel):
    symbol: str
    exchange: str
    qty: int
    amount: float
    action: str
    orderType: str
    instrument_token: Optional[int] = None
    exchange_token: Optional[int] = None

class ReportEditor(BaseModel):
    report_path: str
    new_content: str

class PortfolioFilterParams(BaseModel):
    investor: Optional[str] = None

class PortfolioHolding(BaseModel):
    symbol: str
    qty: int
    avg_price: float

class ReportList(BaseModel):
    symbol: str
    avg_price: float
    qty: int

class PortfolioReportList(BaseModel):
    investor: str
    description: str
    holdings: List[PortfolioHolding]

class SortField(str, Enum):
    symbol = "symbol"
    qty = "qty"
    avg_price = "avg_price"

class SortOrder(str, Enum):
    asc = "asc"
    desc = "desc"

class ReportType(BaseModel):
    reqType: int
    start_date: Optional[str] = None
    end_date: Optional[str] = None
    exchange: Optional[str]= None
    instrument: int = 0 
    length: int = 10
    offset: int = 0
    sort_field: Optional[SortField] = None
    sort_order: SortOrder = SortOrder.asc

    @root_validator(pre=True)
    def set_default_dates(cls, values):
        if values.get("start_date") is None and values.get("end_date") is None:
            end_date = datetime.today()
            start_date = end_date - timedelta(days=30)
            values["start_date"] = start_date.strftime("%Y-%m-%d")
            values["end_date"] = end_date.strftime("%Y-%m-%d")
        return values

class PriceData(TypedDict):
    date: datetime
    price_multiplied: float

class SymbolReport(TypedDict):
    type: str
    symbol: str
    qty: Union[float, str]
    avg_price: Union[float, str]

class Order(BaseModel):
    symbol: str
    amount: float
    quantity: int
    exchange: str
    action: str
    instrument_token: Optional[int] = None
    exchange_token: Optional[int] = None

class DeleteOrd(BaseModel):
    order_id: list[Dict[str, str]]

class User(BaseModel):
    username: str
    email: str
    password: str

class UserInDB(User):
    hashed_password: str

class FilterItem(BaseModel):
    filter: str
    condition: str
    value: Union[str, List[str]] = Field(..., description="The value to evaluate against the filter. Can be a single string or a list of strings.")
    operator: Optional[str] = None

class ReportDetails_NSE(BaseModel):
    input_symbol: Optional[str] = None
    duration: Optional[str] = Field(default="1Y")
    Instrument: Optional[str] = Field(default="Equity")
    start_date: Optional[str] = None
    end_date: Optional[str] = None
    type: Optional[int] = 0
    filters: Optional[List[FilterItem]] = None

class ReportDetails_BSE(BaseModel):
    input_symbol: Optional[str] = None
    duration: Optional[str] = Field(default="1Y")
    Instrument: Optional[str] = Field(default="Equity")
    start_date: Optional[str] = None
    end_date: Optional[str] = None
    type: Optional[int] = 0
    filters: Optional[List[FilterItem]] = None

class ConditionItem_test(BaseModel):
    filter: str
    condition: str
    value: Union[str, List[str]] = Field(
        ..., description="The value to evaluate against the filter. Can be a single string or a list of strings."
    )
    operator: Optional[str] = None


class FilterItem_test(BaseModel):
    timeRange: List[str] = Field(
        ..., description="The start and end dates for the time range in the format [start_date, end_date]."
    )
    conditions: List[ConditionItem_test] = Field(
        ..., description="A list of conditions to apply within this filter."
    )

class ReportDetails_test(BaseModel):
    input_symbol: Optional[str] = None
    duration: Optional[str] = Field(default="1Y")
    Instrument: Optional[str] = Field(default="Equity")
    start_date: Optional[str] = None
    end_date: Optional[str] = None
    type: Optional[int] = 0
    filters: Optional[List[FilterItem_test]] = None

class PortfolioDelete(BaseModel):
    investorName: str

class Condition(BaseModel):
    filter: str
    condition: str
    value: str
    operator: str

class TimeRangeQuery(BaseModel):
    timeRange: List[str]
    conditions: List[Condition]

class QueryStore(BaseModel):
    queryName: str
    report_type: str
    description: Optional[str] = ""
    payload: List[TimeRangeQuery]

class SecCondition(BaseModel):
    filter: str
    condition: str
    value: str
    operator: str

class SecPayload(BaseModel):
    timeRange: List[str]
    conditions: List[SecCondition]

class SecQuery(BaseModel):
    queryName: str
    description: str
    payload: List[SecPayload]
    report_type: str

class Section(BaseModel):
    sectionName: str
    description: str
    # Queries: List[SecQuery]
    Queries: str
    queryType: str
    report_type: str

class PricesAPI(BaseModel):
    exchange: str
    symbol: str
    start_date: Optional[str] = "2024-01-01"
    end_date: Optional[str] = str(date.today())
