from typing import List

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session

from src.infrastructure.database.connection import get_db
from src.infrastructure.repositories.sql_merchant_repository import SqlMerchantRepository
from src.application.use_cases.get_merchants import GetMerchantsUseCase, GetMerchantByIdUseCase
from src.application.use_cases.merchant.get_locations import GetMerchantLocationsUseCase
from src.application.use_cases.merchant.create_location import CreateMerchantLocationUseCase
from src.application.use_cases.merchant.update_location import UpdateMerchantLocationUseCase
from src.application.use_cases.merchant.get_location import GetLocationUseCase
from src.core.exceptions import NotFoundException
from src.presentation.api.v1.merchants.schemas import (
    MerchantListResponse,
    MerchantResponse,
    MerchantLocationResponse,
    CreateLocationRequest,
    UpdateLocationRequest,
)

router = APIRouter(prefix="/merchants", tags=["Merchants"])


@router.get("/", response_model=List[MerchantListResponse])
def get_merchants(db: Session = Depends(get_db)):
    """Fetch merchant list with category name, resolved status, pending docs and agreement flag."""
    repo = SqlMerchantRepository(db)
    use_case = GetMerchantsUseCase(merchant_repo=repo)
    items = use_case.execute()
    return [
        MerchantListResponse(
            id=item.id,
            merchant_name=item.merchant_name,
            category_name=item.category_name,
            slug=item.slug,
            status=item.status,
            code=item.code,
            contact_number=item.contact_number,
            is_guest_active=item.is_guest_active,
            is_agreement_signed=item.is_agreement_signed,
            has_module=item.has_module,
            pending_docs=getattr(item, "_pending_docs", []),
        )
        for item in items
    ]


@router.get("/{merchant_id}", response_model=MerchantResponse)
def get_merchant_by_id(merchant_id: int, db: Session = Depends(get_db)):
    """Fetch a single merchant by ID."""
    repo = SqlMerchantRepository(db)
    use_case = GetMerchantByIdUseCase(merchant_repo=repo)
    try:
        return use_case.execute(merchant_id)
    except NotFoundException as e:
        raise HTTPException(status_code=404, detail=str(e))


@router.get("/{merchant_id}/locations", response_model=List[MerchantLocationResponse])
def get_merchant_locations(merchant_id: int, db: Session = Depends(get_db)):
    repo = SqlMerchantRepository(db)
    use_case = GetMerchantLocationsUseCase(repo)
    return use_case.execute(merchant_id)


@router.post("/{merchant_id}/locations", response_model=MerchantLocationResponse)
def create_location(merchant_id: int, payload: CreateLocationRequest, db: Session = Depends(get_db)):
    repo = SqlMerchantRepository(db)
    use_case = CreateMerchantLocationUseCase(repo)
    return use_case.execute(merchant_id, payload.dict())


@router.get("/locations/{location_id}", response_model=MerchantLocationResponse)
def get_location(location_id: int, db: Session = Depends(get_db)):
    repo = SqlMerchantRepository(db)
    use_case = GetLocationUseCase(repo)
    location = use_case.execute(location_id)
    if not location:
        raise HTTPException(status_code=404, detail="Location not found")
    return location


@router.put("/locations/{location_id}", response_model=MerchantLocationResponse)
def update_location(location_id: int, payload: UpdateLocationRequest, db: Session = Depends(get_db)):
    repo = SqlMerchantRepository(db)
    use_case = UpdateMerchantLocationUseCase(repo)
    location = use_case.execute(location_id, payload.dict(exclude_unset=True))
    if not location:
        raise HTTPException(status_code=404, detail="Location not found")
    return location
