from sqlalchemy.orm import Session
from fastapi import HTTPException, status
from typing import List, Optional
from . import repository
from .schema import (
    GradingserviceCreate,
    GradingserviceUpdate,
    GradedcardCreate,
    GradedcardUpdate,
)
from listing_management import repository as listing_repo


# Gradingservice handlers
def create_gradingservice(db: Session, data: GradingserviceCreate):
    existing_name = repository.get_by_name(db, data.name)
    if existing_name:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=f"Grading service with name '{data.name}' already exists"
        )
    
    existing_abbr = repository.get_by_abbreviation(db, data.abbreviation)
    if existing_abbr:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=f"Grading service with abbreviation '{data.abbreviation}' already exists"
        )
    
    try:
        grading_service = repository.create(db, data.model_dump())
        db.commit()
        db.refresh(grading_service)
        return grading_service
    except Exception:
        db.rollback()
        raise


def get_gradingservice(db: Session, gradingservice_id: str):
    grading_service = repository.get_by_id(db, gradingservice_id)
    if not grading_service:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Grading service with id '{gradingservice_id}' not found"
        )
    return grading_service


def list_gradingservices(
    db: Session,
    limit: int = 20,
    offset: int = 0,
    name: Optional[str] = None,
    abbreviation: Optional[str] = None
) -> List:
    filters = {}
    if name:
        filters["name"] = name
    if abbreviation:
        filters["abbreviation"] = abbreviation
    
    return repository.list_all(db, limit, offset, **filters)


def update_gradingservice(db: Session, gradingservice_id: str, data: GradingserviceUpdate):
    grading_service = repository.get_by_id(db, gradingservice_id)
    if not grading_service:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Grading service with id '{gradingservice_id}' not found"
        )
    
    update_data = data.model_dump(exclude_unset=True)
    
    if "name" in update_data and update_data["name"] != grading_service.name:
        existing_name = repository.get_by_name(db, update_data["name"])
        if existing_name:
            raise HTTPException(
                status_code=status.HTTP_409_CONFLICT,
                detail=f"Grading service with name '{update_data['name']}' already exists"
            )
    
    if "abbreviation" in update_data and update_data["abbreviation"] != grading_service.abbreviation:
        existing_abbr = repository.get_by_abbreviation(db, update_data["abbreviation"])
        if existing_abbr:
            raise HTTPException(
                status_code=status.HTTP_409_CONFLICT,
                detail=f"Grading service with abbreviation '{update_data['abbreviation']}' already exists"
            )
    
    try:
        updated_service = repository.update(db, gradingservice_id, update_data)
        db.commit()
        db.refresh(updated_service)
        return updated_service
    except Exception:
        db.rollback()
        raise


def delete_gradingservice(db: Session, gradingservice_id: str):
    grading_service = repository.get_by_id(db, gradingservice_id)
    if not grading_service:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Grading service with id '{gradingservice_id}' not found"
        )
    
    try:
        repository.delete(db, gradingservice_id)
        db.commit()
        return {"message": "Grading service deleted successfully"}
    except Exception:
        db.rollback()
        raise


# Gradedcard handlers
def create_gradedcard(db: Session, data: GradedcardCreate):
    listing = listing_repo.get_by_id(db, data.listing_id)
    if not listing:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Listing with id '{data.listing_id}' not found"
        )
    
    existing_graded = repository.get_gradedcard_by_listing_id(db, data.listing_id)
    if existing_graded:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=f"Listing '{data.listing_id}' already has a graded card record"
        )
    
    grading_service = repository.get_by_id(db, data.grading_service_id)
    if not grading_service:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Grading service with id '{data.grading_service_id}' not found"
        )
    
    if data.certification_number:
        existing_cert = repository.get_gradedcard_by_certification_number(db, data.certification_number)
        if existing_cert:
            raise HTTPException(
                status_code=status.HTTP_409_CONFLICT,
                detail=f"Certification number '{data.certification_number}' already exists"
            )
    
    try:
        graded_card = repository.create_gradedcard(db, data.model_dump())
        db.commit()
        db.refresh(graded_card)
        return graded_card
    except Exception:
        db.rollback()
        raise


def get_gradedcard(db: Session, gradedcard_id: str):
    graded_card = repository.get_gradedcard_by_id(db, gradedcard_id)
    if not graded_card:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Graded card with id '{gradedcard_id}' not found"
        )
    return graded_card


def get_gradedcard_details(db: Session, gradedcard_id: str):
    graded_card = repository.get_gradedcard_with_details(db, gradedcard_id)
    if not graded_card:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Graded card with id '{gradedcard_id}' not found"
        )
    return graded_card


def list_gradedcards(
    db: Session,
    limit: int = 20,
    offset: int = 0,
    listing_id: Optional[str] = None,
    grading_service_id: Optional[str] = None,
    grade: Optional[str] = None,
    certification_number: Optional[str] = None
) -> List:
    filters = {}
    if listing_id:
        filters["listing_id"] = listing_id
    if grading_service_id:
        filters["grading_service_id"] = grading_service_id
    if grade:
        filters["grade"] = grade
    if certification_number:
        filters["certification_number"] = certification_number
    
    return repository.list_gradedcards(db, limit, offset, **filters)


def update_gradedcard(db: Session, gradedcard_id: str, data: GradedcardUpdate):
    graded_card = repository.get_gradedcard_by_id(db, gradedcard_id)
    if not graded_card:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Graded card with id '{gradedcard_id}' not found"
        )
    
    update_data = data.model_dump(exclude_unset=True)
    
    if "listing_id" in update_data and update_data["listing_id"] != graded_card.listing_id:
        listing = listing_repo.get_by_id(db, update_data["listing_id"])
        if not listing:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"Listing with id '{update_data['listing_id']}' not found"
            )
        
        existing_graded = repository.get_gradedcard_by_listing_id(db, update_data["listing_id"])
        if existing_graded:
            raise HTTPException(
                status_code=status.HTTP_409_CONFLICT,
                detail=f"Listing '{update_data['listing_id']}' already has a graded card record"
            )
    
    if "grading_service_id" in update_data:
        grading_service = repository.get_by_id(db, update_data["grading_service_id"])
        if not grading_service:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"Grading service with id '{update_data['grading_service_id']}' not found"
            )
    
    if "certification_number" in update_data and update_data["certification_number"]:
        if update_data["certification_number"] != graded_card.certification_number:
            existing_cert = repository.get_gradedcard_by_certification_number(db, update_data["certification_number"])
            if existing_cert:
                raise HTTPException(
                    status_code=status.HTTP_409_CONFLICT,
                    detail=f"Certification number '{update_data['certification_number']}' already exists"
                )
    
    try:
        updated_card = repository.update_gradedcard(db, gradedcard_id, update_data)
        db.commit()
        db.refresh(updated_card)
        return updated_card
    except Exception:
        db.rollback()
        raise


def delete_gradedcard(db: Session, gradedcard_id: str):
    graded_card = repository.get_gradedcard_by_id(db, gradedcard_id)
    if not graded_card:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Graded card with id '{gradedcard_id}' not found"
        )
    
    try:
        repository.delete_gradedcard(db, gradedcard_id)
        db.commit()
        return {"message": "Graded card deleted successfully"}
    except Exception:
        db.rollback()
        raise