from datetime import datetime, timezone, date
from typing import Optional

from fastapi import APIRouter, Query, status
import random
import string
from repositories.service_repository import ServiceRepository
from repositories.user_repository import UserRepository
from repositories.appointment_repository import AppointmentRepository
from schemas.service import ServiceSchema, CreateServiceRequest, UpdateServiceRequest
from schemas.appointment import CreateAppointmentRequest, AppointmentResponseSchema
from utils.auth_dependency import handles_authentication, user_dependency
from utils.database import db_dependency
from utils.exceptions import NotFoundException, AuthenticationError
from utils.response import Response, ObjectResponseModel, ListResponseModel, BaseResponseModel

router = APIRouter(prefix="/api/appointments", tags=["Appointments"])



def generate_code():
    # Generate 6 digits
    digits = ''.join(random.choices(string.digits, k=6))
    # Generate 1 uppercase letter
    letter = random.choice(string.ascii_uppercase)

    # Insert the letter at a random position in the digits string
    pos = random.randint(0, len(digits))
    code = digits[:pos] + letter + digits[pos:]
    return code

@router.post("/create", status_code=status.HTTP_201_CREATED, response_model=ObjectResponseModel)
@handles_authentication
async def create_appointment(
    user: user_dependency,
    request: CreateAppointmentRequest,
    db: db_dependency
):
    if user is None:
        raise AuthenticationError

    user_repo = UserRepository(db)
    appointment_repo = AppointmentRepository(db)

    user = await user_repo.get_by_email(user.get('email'), convert_to_entity=False)
    if not user or not user.default_company:
        raise NotFoundException("Company")
    appointment_code = generate_code()
    created_appointment = await appointment_repo.create_appointment(
        company_id=user.default_company,
        appointment_no= appointment_code,
        name=request.name,
        phone=request.phone,
        start_datetime=request.start_datetime,
        end_datetime=request.end_datetime,
        service_id=request.service_id,
        summary=request.summary
    )

    return Response.post(created_appointment, "Appointment")


@router.get("/read_all", status_code=status.HTTP_200_OK, response_model=ListResponseModel)
@handles_authentication
async def get_appointments(
    user: user_dependency,
    db: db_dependency,
    start: int = Query(0, ge=0),
    limit: int = Query(10, ge=1, le=100),
    appointment_date: Optional[date] = Query(None, description="Filter appointments by date")
):
    user_repo = UserRepository(db)
    appointment_repo = AppointmentRepository(db)

    user = await user_repo.get_by_email(user.get('email'), convert_to_entity=False)
    if not user or not user.default_company:
        raise NotFoundException("Company")

    result = await appointment_repo.get_by_company(
        user.default_company,
        start,
        limit,
        appointment_date
    )
    return Response.get_list(
        name="Appointments",
        collection=result["data"],
        page_size=limit,
        total=result["total_count"]
    )


@router.post("/{appointment_id}/cancel", status_code=status.HTTP_200_OK, response_model=BaseResponseModel)
async def cancel_appointment(
    appointment_id: int,
    user: user_dependency,
    db: db_dependency
):
    if user is None:
        raise AuthenticationError

    user_repo = UserRepository(db)
    appointment_repo = AppointmentRepository(db)

    user = await user_repo.get_by_email(user.get('email'), convert_to_entity=False)
    if not user or not user.default_company:
        raise NotFoundException("Company")

    cancelled = await appointment_repo.cancel_appointment(appointment_id, user.default_company)
    if not cancelled:
        raise NotFoundException("Appointment")

    return Response.cancel(name="Appointment")