from fastapi import APIRouter, Depends, Query, status
from sqlalchemy.orm import Session
from typing import Optional, List
from datetime import date
from decimal import Decimal
from utils.utils import get_db
from . import handler
from .schema import (
    SectorCreate, SectorUpdate, SectorResponse,
    ExchangeCreate, ExchangeUpdate, ExchangeResponse,
    StockCreate, StockUpdate, StockResponse, StockDetailResponse,
    StockhistoryCreate, StockhistoryUpdate, StockhistoryResponse,
    StockWithHistoryResponse, BulkImportStocksRequest, BulkImportStocksResponse,
    BulkImportHistoryRequest, BulkImportHistoryResponse
)

router = APIRouter(prefix="/stock-management", tags=["Stock Management"])


# Sector routes
@router.post(
    "/sectors",
    response_model=SectorResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Sector",
    description="Creates a new sector record. Validates that the sector name is unique. Returns 409 if a sector with the same name already exists.",
)
def create_sector_route(data: SectorCreate, db: Session = Depends(get_db)):
    return handler.create_sector(db, data)


@router.get(
    "/sectors",
    response_model=List[SectorResponse],
    summary="List Sectors",
    description="Returns a paginated list of sectors ordered by display_order and name. Supports optional search filter on sector name.",
)
def list_sectors_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    search: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_sectors(db, limit, offset, search)


@router.get(
    "/sectors/{sector_id}",
    response_model=SectorResponse,
    summary="Get Sector",
    description="Retrieves a single sector by ID. Returns 404 if the sector does not exist.",
)
def get_sector_route(sector_id: str, db: Session = Depends(get_db)):
    return handler.get_sector(db, sector_id)


@router.put(
    "/sectors/{sector_id}",
    response_model=SectorResponse,
    summary="Update Sector",
    description="Updates an existing sector. Validates that the new name is unique if changed. Returns 404 if sector not found, 409 if name conflict.",
)
def update_sector_route(sector_id: str, data: SectorUpdate, db: Session = Depends(get_db)):
    return handler.update_sector(db, sector_id, data)


@router.delete(
    "/sectors/{sector_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Sector",
    description="Deletes a sector. Returns 404 if sector not found, 409 if sector is referenced by existing stocks.",
)
def delete_sector_route(sector_id: str, db: Session = Depends(get_db)):
    return handler.delete_sector(db, sector_id)


# Exchange routes
@router.post(
    "/exchanges",
    response_model=ExchangeResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Exchange",
    description="Creates a new exchange record. Validates that the exchange code is unique. Returns 409 if an exchange with the same code already exists.",
)
def create_exchange_route(data: ExchangeCreate, db: Session = Depends(get_db)):
    return handler.create_exchange(db, data)


@router.get(
    "/exchanges",
    response_model=List[ExchangeResponse],
    summary="List Exchanges",
    description="Returns a paginated list of exchanges ordered by name. Supports optional search filter on name or code, and country filter.",
)
def list_exchanges_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    search: Optional[str] = None,
    country: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_exchanges(db, limit, offset, search, country)


@router.get(
    "/exchanges/{exchange_id}",
    response_model=ExchangeResponse,
    summary="Get Exchange",
    description="Retrieves a single exchange by ID. Returns 404 if the exchange does not exist.",
)
def get_exchange_route(exchange_id: str, db: Session = Depends(get_db)):
    return handler.get_exchange(db, exchange_id)


@router.put(
    "/exchanges/{exchange_id}",
    response_model=ExchangeResponse,
    summary="Update Exchange",
    description="Updates an existing exchange. Validates that the new code is unique if changed. Returns 404 if exchange not found, 409 if code conflict.",
)
def update_exchange_route(exchange_id: str, data: ExchangeUpdate, db: Session = Depends(get_db)):
    return handler.update_exchange(db, exchange_id, data)


@router.delete(
    "/exchanges/{exchange_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Exchange",
    description="Deletes an exchange. Returns 404 if exchange not found, 409 if exchange is referenced by existing stocks.",
)
def delete_exchange_route(exchange_id: str, db: Session = Depends(get_db)):
    return handler.delete_exchange(db, exchange_id)


# Stock routes
@router.post(
    "/stocks",
    response_model=StockResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Stock",
    description="Creates a new stock record. Validates ticker symbol and company name uniqueness, sector and exchange existence, and price business rules (high >= low, open/close between low and high). Returns 400 for validation errors, 409 for conflicts.",
)
def create_stock_route(data: StockCreate, db: Session = Depends(get_db)):
    return handler.create_stock(db, data)


@router.get(
    "/stocks",
    response_model=List[StockResponse],
    summary="List Stocks",
    description="Returns a paginated list of stocks ordered by ticker symbol. Supports search on ticker or company name, and filters by sector, exchange, status, and price range.",
)
def list_stocks_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    search: Optional[str] = None,
    sector_id: Optional[str] = None,
    exchange_id: Optional[str] = None,
    status_filter: Optional[str] = None,
    min_price: Optional[Decimal] = None,
    max_price: Optional[Decimal] = None,
    db: Session = Depends(get_db),
):
    return handler.list_stocks(db, limit, offset, search, sector_id, exchange_id, status_filter, min_price, max_price)


@router.get(
    "/stocks/{stock_id}",
    response_model=StockResponse,
    summary="Get Stock",
    description="Retrieves a single stock by ID. Returns 404 if the stock does not exist.",
)
def get_stock_route(stock_id: str, db: Session = Depends(get_db)):
    return handler.get_stock(db, stock_id)


@router.get(
    "/stocks/{stock_id}/details",
    response_model=StockDetailResponse,
    summary="Get Stock Details",
    description="Retrieves a stock with eagerly loaded sector and exchange details. Returns 404 if the stock does not exist.",
)
def get_stock_details_route(stock_id: str, db: Session = Depends(get_db)):
    return handler.get_stock_details(db, stock_id)


@router.get(
    "/stocks/{stock_id}/history",
    response_model=StockWithHistoryResponse,
    summary="Get Stock With History",
    description="Retrieves a stock with all historical price data eagerly loaded. Returns 404 if the stock does not exist.",
)
def get_stock_with_history_route(stock_id: str, db: Session = Depends(get_db)):
    return handler.get_stock_with_history(db, stock_id)


@router.get(
    "/stocks/search/autocomplete",
    response_model=List[StockResponse],
    summary="Search Stocks Autocomplete",
    description="Searches active stocks by ticker or company name for autocomplete suggestions. Returns up to 10 results. Requires at least 1 character search term.",
)
def search_stocks_autocomplete_route(
    search: str = Query(..., min_length=1),
    db: Session = Depends(get_db),
):
    return handler.search_stocks_autocomplete(db, search)


@router.put(
    "/stocks/{stock_id}",
    response_model=StockResponse,
    summary="Update Stock",
    description="Updates an existing stock. Validates ticker and company name uniqueness if changed, sector and exchange existence, and price business rules. Updates last_updated timestamp. Returns 400 for validation errors, 404 if not found, 409 for conflicts.",
)
def update_stock_route(stock_id: str, data: StockUpdate, db: Session = Depends(get_db)):
    return handler.update_stock(db, stock_id, data)


@router.delete(
    "/stocks/{stock_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Stock",
    description="Soft deletes a stock by marking its status as INACTIVE. Returns 404 if stock not found.",
)
def delete_stock_route(stock_id: str, db: Session = Depends(get_db)):
    return handler.delete_stock(db, stock_id)


@router.post(
    "/stocks/bulk-import",
    response_model=BulkImportStocksResponse,
    status_code=status.HTTP_200_OK,
    summary="Bulk Import Stocks",
    description="Imports multiple stocks from a list. Validates each stock, checks sector and exchange existence, and ensures ticker and company name uniqueness. Returns a summary with total, successful, failed counts and error details. Maximum 10,000 rows per import.",
)
def bulk_import_stocks_route(data: BulkImportStocksRequest, db: Session = Depends(get_db)):
    return handler.bulk_import_stocks(db, data)


# StockHistory routes
@router.post(
    "/stock-history",
    response_model=StockhistoryResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Stock History",
    description="Creates a new stock history record. Validates stock existence, uniqueness of stock_id and date combination, and price business rules (high >= low, open/close between low and high). Returns 400 for validation errors, 409 for conflicts.",
)
def create_stockhistory_route(data: StockhistoryCreate, db: Session = Depends(get_db)):
    return handler.create_stockhistory(db, data)


@router.get(
    "/stock-history",
    response_model=List[StockhistoryResponse],
    summary="List Stock History",
    description="Returns a paginated list of stock history records ordered by date descending. Supports filters by stock_id, start_date, and end_date.",
)
def list_stockhistory_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    stock_id: Optional[str] = None,
    start_date: Optional[date] = None,
    end_date: Optional[date] = None,
    db: Session = Depends(get_db),
):
    return handler.list_stockhistory(db, limit, offset, stock_id, start_date, end_date)


@router.get(
    "/stock-history/{stockhistory_id}",
    response_model=StockhistoryResponse,
    summary="Get Stock History",
    description="Retrieves a single stock history record by ID. Returns 404 if the record does not exist.",
)
def get_stockhistory_route(stockhistory_id: str, db: Session = Depends(get_db)):
    return handler.get_stockhistory(db, stockhistory_id)


@router.put(
    "/stock-history/{stockhistory_id}",
    response_model=StockhistoryResponse,
    summary="Update Stock History",
    description="Updates an existing stock history record. Validates stock existence if changed, uniqueness of stock_id and date if changed, and price business rules. Returns 400 for validation errors, 404 if not found, 409 for conflicts.",
)
def update_stockhistory_route(stockhistory_id: str, data: StockhistoryUpdate, db: Session = Depends(get_db)):
    return handler.update_stockhistory(db, stockhistory_id, data)


@router.delete(
    "/stock-history/{stockhistory_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Stock History",
    description="Deletes a stock history record. Returns 404 if the record does not exist.",
)
def delete_stockhistory_route(stockhistory_id: str, db: Session = Depends(get_db)):
    return handler.delete_stockhistory(db, stockhistory_id)


@router.post(
    "/stock-history/bulk-import",
    response_model=BulkImportHistoryResponse,
    status_code=status.HTTP_200_OK,
    summary="Bulk Import Stock History",
    description="Imports multiple stock history records from a list. Validates each record, checks stock existence by ticker symbol, ensures uniqueness of stock and date combination, and validates price business rules. Returns a summary with total, successful, failed counts and error details. Maximum 10,000 rows per import.",
)
def bulk_import_stock_history_route(data: BulkImportHistoryRequest, db: Session = Depends(get_db)):
    return handler.bulk_import_stock_history(db, data)