from flask.views import MethodView
from flask_smorest import Blueprint
from flask import request
from src.views.availability.utils import TutorAvailabilityManager, SupervisorAvailabilityManager
from src.models.schema import (
    TutorAvailabilitySchema
)
from src.utils import custom_response
from datetime import datetime
from src.models import DatabaseContextManager
from src.models.models import SupervisorAvailability, Supervisor
from sqlalchemy.orm import joinedload

tutor_availability = Blueprint("Tutor Availability Management Routes", __name__, description="Operations related to student management")

@tutor_availability.route("/tutors/<string:tutor_id>/availability")
class TutorAvailabilityRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = TutorAvailabilityManager()

    @tutor_availability.response(status_code=200, schema=TutorAvailabilitySchema(many=True))
    def get(self, tutor_id):
        """Get all approved availabilities for a tutor"""
        return self.availability_manager.get_approved_availabilities(tutor_id)
    
    @tutor_availability.response(status_code=201)
    def post(self, tutor_id):
        """Create new availability slots for a tutor (requires supervisor approval)"""
        payload = request.get_json()
        return self.availability_manager.create(tutor_id, payload)
    

@tutor_availability.route("/tutors/availability/<user_id>")
class AvailabilityRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = TutorAvailabilityManager()

    def get(self, user_id):
        """Get availabilities - handles both supervisor and tutor cases"""
        return self.availability_manager.fetchAll(user_id)

# Supervisor Availability Routes
@tutor_availability.route("/supervisors/<string:supervisor_id>/availability")
class SupervisorAvailabilityRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = SupervisorAvailabilityManager()

    def get(self, supervisor_id):
        """Get all approved availabilities for a supervisor"""
        with DatabaseContextManager() as ctx:
            availabilities = ctx.session.query(SupervisorAvailability).options(
                joinedload(SupervisorAvailability.supervisor)
            ).filter(
                SupervisorAvailability.supervisor_id == supervisor_id,
                SupervisorAvailability.is_approved == True,
                SupervisorAvailability.is_cancelled == False
            ).all()

            # Convert to dictionary format
            availability_list = []
            for avail in availabilities:
                availability_list.append({
                    'id': avail.id,
                    'supervisor_id': avail.supervisor_id,
                    'day_of_week': avail.day_of_week,
                    'day_name': ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][avail.day_of_week] if 0 <= avail.day_of_week < 7 else 'Unknown',
                    'start_time': avail.start_time.strftime('%H:%M'),
                    'end_time': avail.end_time.strftime('%H:%M'),
                    'is_recurring': avail.is_recurring,
                    'valid_from': avail.valid_from.isoformat() if avail.valid_from else None,
                    'valid_to': avail.valid_to.isoformat() if avail.valid_to else None,
                    'is_approved': avail.is_approved,
                    'availability_type': avail.availability_type,
                    'location': avail.location,
                    'notes': avail.notes,
                    'created_at': avail.created_at.isoformat() if avail.created_at else None,
                    'user_type': 'supervisor',
                    'supervisor': {
                        'id': avail.supervisor.id,
                        'first_name': avail.supervisor.first_name,
                        'last_name': avail.supervisor.last_name,
                        'email': avail.supervisor.email
                    },
                    'supervisor_name': f"{avail.supervisor.first_name} {avail.supervisor.last_name}"
                })

            return custom_response(
                success=True,
                data=availability_list,
                status_code=200
            )
    
    def post(self, supervisor_id):
        """Create new availability slots for a supervisor"""
        payload = request.get_json()
        return self.availability_manager.create_supervisor_availability(supervisor_id, payload)

@tutor_availability.route("/supervisors/<string:supervisor_id>/availability/<string:availability_id>")
class SupervisorSingleAvailabilityRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = SupervisorAvailabilityManager()

    def get(self, supervisor_id, availability_id):
        """Get a specific supervisor availability slot"""
        return self.availability_manager.get(availability_id)

    def put(self, supervisor_id, availability_id):
        """Update a supervisor availability slot"""
        payload = request.get_json()
        return self.availability_manager.update_supervisor_availability(availability_id, payload)

    def delete(self, supervisor_id, availability_id):
        """Delete a supervisor availability slot"""
        return self.availability_manager.delete_supervisor_availability(availability_id)

@tutor_availability.route("/tutors/<string:tutor_id>/availability/pending")
class TutorPendingAvailabilityRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = TutorAvailabilityManager()

    @tutor_availability.response(status_code=200, schema=TutorAvailabilitySchema(many=True))
    def get(self, tutor_id):
        """Get all pending approval availabilities for a tutor"""
        return self.availability_manager.get_tutor_availabilities(tutor_id, include_pending=True)

@tutor_availability.route("/tutors/<string:tutor_id>/availability/<string:availability_id>")
class TutorSingleAvailabilityRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = TutorAvailabilityManager()

    @tutor_availability.response(status_code=200, schema=TutorAvailabilitySchema)
    def get(self, tutor_id, availability_id):
        """Get a specific availability slot"""
        return self.availability_manager.get(availability_id)

    @tutor_availability.arguments(schema=TutorAvailabilitySchema, location='json')
    @tutor_availability.response(status_code=200)
    def put(self, payload, tutor_id, availability_id):
        """Update an availability slot"""
        return self.availability_manager.update(availability_id, payload)

    @tutor_availability.response(status_code=204)
    def delete(self, tutor_id, availability_id):
        """Delete an availability slot"""
        return self.availability_manager.delete(availability_id)

@tutor_availability.route("/tutors/<string:tutor_id>/availability/check")
class TutorAvailabilityCheckRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = TutorAvailabilityManager()

    @tutor_availability.response(status_code=200)
    def get(self, tutor_id):
        """Check if tutor is available at a specific time"""
        start_time = request.args.get('start_time')
        end_time = request.args.get('end_time')
        
        try:
            start_datetime = datetime.fromisoformat(start_time)
            end_datetime = datetime.fromisoformat(end_time)
            return self.availability_manager.check_availability(tutor_id, start_datetime, end_datetime)
        except ValueError:
            return custom_response(
                success=False,
                data="Invalid datetime format. Use ISO format (YYYY-MM-DDTHH:MM:SS)",
                status_code=400
            )

@tutor_availability.route("/tutors/<string:tutor_id>/availability/weekly")
class TutorWeeklyAvailabilityRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = TutorAvailabilityManager()

    @tutor_availability.response(status_code=200)
    def get(self, tutor_id):
        """Get tutor's weekly availability"""
        week_start = request.args.get('week_start')
        if week_start:
            try:
                week_start = datetime.strptime(week_start, '%Y-%m-%d').date()
            except ValueError:
                return custom_response(
                    success=False,
                    data="Invalid date format. Use YYYY-MM-DD",
                    status_code=400
                )
        return self.availability_manager.get_weekly_availability(tutor_id, week_start)

@tutor_availability.route("/supervisors/<string:supervisor_id>/availability/approvals")
class SupervisorAvailabilityApprovalRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = TutorAvailabilityManager()

    @tutor_availability.response(status_code=200)
    def get(self, supervisor_id):
        """Get all availability slots pending approval for tutors supervised by this supervisor"""
        return self.availability_manager.get_pending_approvals(supervisor_id)

    @tutor_availability.arguments(schema=TutorAvailabilitySchema, location='json')
    @tutor_availability.response(status_code=200)
    def post(self, payload, supervisor_id):
        """Bulk approve availability slots"""
        availability_ids = payload.get('availability_ids', [])
        return self.availability_manager.bulk_approve(supervisor_id, availability_ids)

@tutor_availability.route("/supervisors/<string:supervisor_id>/availability/approve/<string:availability_id>")
class SupervisorSingleApprovalRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = TutorAvailabilityManager()

    @tutor_availability.response(status_code=200)
    def post(self, supervisor_id, availability_id):
        """Approve a single availability slot"""
        return self.availability_manager.approve_availability(supervisor_id, availability_id)

@tutor_availability.route("/supervisors/<string:supervisor_id>/availability/reject/<string:availability_id>")
class SupervisorRejectionRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = TutorAvailabilityManager()

    @tutor_availability.arguments(schema=TutorAvailabilitySchema, location='json')
    @tutor_availability.response(status_code=200)
    def post(self, payload, supervisor_id, availability_id):
        """Reject an availability slot"""
        reason = payload.get('reason', 'No reason provided')
        return self.availability_manager.reject_availability(supervisor_id, availability_id, reason)

# Opening Sessions Routes
@tutor_availability.route("/availability/opening-sessions")
class OpeningSessionsRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = TutorAvailabilityManager()

    def get(self):
        """Get all opening sessions"""
        return self.availability_manager.get_opening_sessions()

    def post(self):
        """Create a new opening session"""
        payload = request.get_json()
        return self.availability_manager.create_opening_session(payload)

@tutor_availability.route("/availability/opening-sessions/<string:session_id>")
class OpeningSessionDetailRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = TutorAvailabilityManager()

    def get(self, session_id):
        """Get a specific opening session"""
        return self.availability_manager.get_opening_session(session_id)

    def put(self, session_id):
        """Update an opening session"""
        payload = request.get_json()
        return self.availability_manager.update_opening_session(session_id, payload)

    def delete(self, session_id):
        """Delete an opening session"""
        return self.availability_manager.delete_opening_session(session_id)

@tutor_availability.route("/availability/opening-sessions/<string:session_id>/status")
class OpeningSessionStatusRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = TutorAvailabilityManager()

    def put(self, session_id):
        """Update opening session status"""
        payload = request.get_json()
        return self.availability_manager.update_opening_session_status(session_id, payload)

@tutor_availability.route("/tutors/<string:tutor_id>/availability/auto-generate")
class TutorAutoGenerateAvailabilityRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = TutorAvailabilityManager()

    def post(self, tutor_id):
        """Auto-generate availability slots for a tutor (Monday-Friday, 8AM-6PM)"""
        payload = request.get_json() or {}
        return self.availability_manager.auto_generate_availability(tutor_id, payload)


@tutor_availability.route("/availability/tutors/<string:tutor_id>/availability/auto-generate")
class AvailabilityTutorAutoGenerateRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = TutorAvailabilityManager()

    def post(self, tutor_id):
        """Auto-generate availability slots for a tutor (Monday-Friday, 8AM-6PM) - Frontend compatibility route"""
        payload = request.get_json() or {}
        return self.availability_manager.auto_generate_availability(tutor_id, payload)

@tutor_availability.route("/availability/<string:availability_id>")
class DirectAvailabilityRouter(MethodView):
    def __init__(self) -> None:
        self.availability_manager = TutorAvailabilityManager()

    def get(self, availability_id):
        """Get a specific availability slot by ID"""
        return self.availability_manager.get(availability_id)

    def put(self, availability_id):
        """Update a specific availability slot by ID"""
        payload = request.get_json()
        return self.availability_manager.update(availability_id, payload)

    def delete(self, availability_id):
        """Delete a specific availability slot by ID"""
        return self.availability_manager.delete(availability_id)