from datetime import datetime
from flask import url_for

from app.extensions import db
from app.models import ActivityRegistration, ManagerApprovalRequest
from app.models.enums import ActivityStatus, RegistrationStatus, ApprovalStatus
from app.notifications.service import NotificationService


class RegistrationError(Exception):
    pass


class RegistrationService:
    @staticmethod
    def register_employee(activity, employee, participation_id, form_data):
        now = datetime.utcnow()

        if activity.status != ActivityStatus.PUBLISHED:
            raise RegistrationError("Activity is not open for registration.")
        if activity.registration_open_at and now < activity.registration_open_at:
            raise RegistrationError("Registration has not opened yet.")
        if activity.registration_close_at and now > activity.registration_close_at:
            raise RegistrationError("Registration deadline has passed.")

        existing = ActivityRegistration.query.filter_by(activity_id=activity.id, employee_id=employee.id).first()
        if existing and existing.status not in [RegistrationStatus.CANCELLED]:
            raise RegistrationError("Employee is already registered for this activity.")

        confirmed_count = ActivityRegistration.query.filter(
            ActivityRegistration.activity_id == activity.id,
            ActivityRegistration.status.in_([
                RegistrationStatus.REGISTERED,
                RegistrationStatus.CONFIRMED,
                RegistrationStatus.ATTENDED,
                RegistrationStatus.COMPLETED,
            ]),
        ).count()
        if activity.capacity and confirmed_count >= activity.capacity:
            raise RegistrationError("Activity capacity has been reached.")

        needs_approval = bool(activity.manager_approval_required or activity.working_hours_activity)
        status = RegistrationStatus.PENDING_APPROVAL if needs_approval else RegistrationStatus.CONFIRMED
        approval_status = ApprovalStatus.PENDING if needs_approval else ApprovalStatus.NOT_REQUIRED

        registration = ActivityRegistration(
            participation_id=participation_id,
            activity_id=activity.id,
            employee_id=employee.id,
            status=status,
            approval_status=approval_status,
            mobile=form_data.get("mobile"),
            emergency_contact_name=form_data.get("emergency_contact_name"),
            emergency_contact_phone=form_data.get("emergency_contact_phone"),
            tshirt_size=form_data.get("tshirt_size"),
            dietary_requirements=form_data.get("dietary_requirements"),
            accessibility_requirements=form_data.get("accessibility_requirements"),
            participation_guidelines_accepted=bool(form_data.get("participation_guidelines_accepted")),
            consent_accepted=bool(form_data.get("consent_accepted")),
        )
        db.session.add(registration)
        db.session.flush()

        if needs_approval:
            if not employee.manager_id:
                raise RegistrationError("Reporting manager is not mapped in HRMS.")
            approval = ManagerApprovalRequest(
                registration_id=registration.id,
                employee_id=employee.id,
                manager_id=employee.manager_id,
                status=ApprovalStatus.PENDING,
                note_to_manager=form_data.get("note_to_manager"),
                requested_at=now,
            )
            db.session.add(approval)
            db.session.flush()
            NotificationService.create_in_app(
                employee.manager_id,
                "MANAGER_APPROVAL_REQUESTED",
                "New volunteering approval request",
                f"{employee.full_name} requested approval for {activity.title}.",
                url_for("manager.approval_detail", request_id=approval.id),
            )
            NotificationService.create_in_app(
                employee.id,
                "REGISTRATION_PENDING_APPROVAL",
                "Nomination sent for approval",
                f"Your nomination for {activity.title} is awaiting manager approval.",
                url_for("employee.my_seva"),
            )
        else:
            NotificationService.create_in_app(
                employee.id,
                "REGISTRATION_CONFIRMED",
                "Participation confirmed",
                f"You're confirmed for {activity.title}.",
                url_for("employee.my_seva"),
            )

        db.session.commit()
        return registration
