import logging
from typing import Dict, Any, Optional

from apps.companies.models import CompanyBotSettings
from apps.calls.constants import BotType
from apps.appointments.repositories.appointment_repository import AppointmentRepository

logger = logging.getLogger(__name__)


class AppointmentService:
    """
    Service layer that handles webhook payload normalization and uses the repository.
    Services accept validated data (e.g. BookAppointmentInputSerializer output).
    """

    @staticmethod
    def _extract_common_webhook_data(webhook_payload: Dict[str, Any]) -> Dict[str, Any]:
        """
        Normalize webhook payload into predictable fields.
        """
        args = webhook_payload.get("args") or {}
        call_info = webhook_payload.get("call") or {}
        tel_identifier = (call_info.get("telephony_identifier") or {})

        return {
            "args": args,
            "twilio_call_sid": tel_identifier.get("twilio_call_sid"),
            "to_number": call_info.get("to_number"),
        }

    @staticmethod
    def _get_company_from_phone(phone_number: Optional[str]):
        """
        Return Company instance matched from CompanyBotSettings or None if not found.
        This is defensive: original code used .first().company and would AttributeError
        if missing; returning None prevents server 500s. If your business rules require
        raising on missing setting, change this accordingly.
        """
        if not phone_number:
            logger.warning("No phone number provided in webhook to lookup company.")
            return None

        cbs = CompanyBotSettings.objects.filter(phone_number=phone_number).first()
        if not cbs:
            logger.warning("CompanyBotSettings not found for phone: %s", phone_number)
            return None
        return cbs.company

    @staticmethod
    def book_sales_bot_appointment(validated_payload: Dict[str, Any]) -> Dict[str, Any]:
        """
        Book an appointment for sales bot using normalized payload.
        Returns a small dict with created flag and appointment id.
        """
        data = AppointmentService._extract_common_webhook_data(validated_payload)
        args = data["args"] or {}
        company = AppointmentService._get_company_from_phone(data.get("to_number"))

        payload = {
            "name": args.get("name"),
            "scheduled_date": args.get("schedule"),
            "offtime": args.get("offTime"),
            "twilio_call_sid": data.get("twilio_call_sid"),
            "company": company,
            "call": None,
            "bot_type": BotType.SALES_BOT.value,
        }

        appointment = AppointmentRepository.create_appointment(payload)

        logger.info(
            "Sales appointment created (id=%s) name=%s scheduled_date=%s company_id=%s",
            appointment.id,
            payload.get("name"),
            payload.get("scheduled_date"),
            getattr(company, "id", None),
        )

        return {"created": True, "appointment_id": appointment.id}

    @staticmethod
    def book_service_bot_appointment(validated_payload: Dict[str, Any]) -> Dict[str, Any]:
        """
        Book an appointment for service bot using normalized payload.
        """
        data = AppointmentService._extract_common_webhook_data(validated_payload)
        args = data["args"] or {}
        company = AppointmentService._get_company_from_phone(data.get("to_number"))

        payload = {
            "name": args.get("name"),
            "appointment_phone": args.get("phone_number"),
            "scheduled_date": args.get("appointment_datetime"),
            "twilio_call_sid": data.get("twilio_call_sid"),
            "company": company,
            "call": None,
            "bot_type": BotType.SERVICE_BOT.value,
        }

        appointment = AppointmentRepository.create_appointment(payload)

        logger.info(
            "Service appointment created (id=%s) name=%s scheduled_date=%s company_id=%s",
            appointment.id,
            payload.get("name"),
            payload.get("scheduled_date"),
            getattr(company, "id", None),
        )

        return {"created": True, "appointment_id": appointment.id}

    @staticmethod
    def get_appointment_by_id(appointment_id: int):
        """
        Retrieve an appointment by its ID.
        """
        return AppointmentRepository.get_by_id(appointment_id)
