from sqlalchemy.orm import Session
from sqlalchemy.exc import IntegrityError
from fastapi import HTTPException, status
from . import repository
from .schema import CalculatordefaultsCreate, CalculatordefaultsUpdate


def get_calculator_defaults(db: Session) -> dict:
    defaults = repository.get_first(db)
    if not defaults:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Calculator defaults not found. System must be initialized with default configuration.")
    return defaults


def get_calculator_defaults_by_id(db: Session, defaults_id: str) -> dict:
    defaults = repository.get_by_id(db, defaults_id)
    if not defaults:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Calculator defaults not found.")
    return defaults


def update_calculator_defaults(db: Session, defaults_id: str, data: CalculatordefaultsUpdate) -> dict:
    defaults = repository.get_by_id(db, defaults_id)
    if not defaults:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Calculator defaults not found.")
    
    update_data = data.model_dump(exclude_unset=True)
    
    if update_data.get("min_principal") is not None and update_data.get("max_principal") is not None:
        if update_data["min_principal"] > update_data["max_principal"]:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Minimum principal cannot exceed maximum principal.")
    elif update_data.get("min_principal") is not None:
        if update_data["min_principal"] > defaults.max_principal:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Minimum principal cannot exceed maximum principal.")
    elif update_data.get("max_principal") is not None:
        if defaults.min_principal > update_data["max_principal"]:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Minimum principal cannot exceed maximum principal.")
    
    if update_data.get("min_interest_rate") is not None and update_data.get("max_interest_rate") is not None:
        if update_data["min_interest_rate"] > update_data["max_interest_rate"]:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Minimum interest rate cannot exceed maximum interest rate.")
    elif update_data.get("min_interest_rate") is not None:
        if update_data["min_interest_rate"] > defaults.max_interest_rate:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Minimum interest rate cannot exceed maximum interest rate.")
    elif update_data.get("max_interest_rate") is not None:
        if defaults.min_interest_rate > update_data["max_interest_rate"]:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Minimum interest rate cannot exceed maximum interest rate.")
    
    if update_data.get("min_term_months") is not None and update_data.get("max_term_months") is not None:
        if update_data["min_term_months"] > update_data["max_term_months"]:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Minimum term cannot exceed maximum term.")
    elif update_data.get("min_term_months") is not None:
        if update_data["min_term_months"] > defaults.max_term_months:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Minimum term cannot exceed maximum term.")
    elif update_data.get("max_term_months") is not None:
        if defaults.min_term_months > update_data["max_term_months"]:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Minimum term cannot exceed maximum term.")
    
    try:
        updated = repository.update(db, defaults_id, update_data)
        db.commit()
        db.refresh(updated)
        return updated
    except IntegrityError as exc:
        db.rollback()
        msg = str(exc.orig).lower() if exc.orig else ""
        if "unique" in msg or "duplicate" in msg:
            raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Resource already exists.")
        if "foreign key" in msg:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Referenced resource does not exist.")
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Data integrity error.")
    except HTTPException:
        db.rollback()
        raise
    except Exception:
        db.rollback()
        raise


def create_calculator_defaults(db: Session, data: CalculatordefaultsCreate) -> dict:
    if data.min_principal > data.max_principal:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Minimum principal cannot exceed maximum principal.")
    if data.min_interest_rate > data.max_interest_rate:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Minimum interest rate cannot exceed maximum interest rate.")
    if data.min_term_months > data.max_term_months:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Minimum term cannot exceed maximum term.")
    
    try:
        defaults = repository.create(db, data.model_dump())
        db.commit()
        db.refresh(defaults)
        return defaults
    except IntegrityError as exc:
        db.rollback()
        msg = str(exc.orig).lower() if exc.orig else ""
        if "unique" in msg or "duplicate" in msg:
            raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Resource already exists.")
        if "foreign key" in msg:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Referenced resource does not exist.")
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Data integrity error.")
    except HTTPException:
        db.rollback()
        raise
    except Exception:
        db.rollback()
        raise