"""Vaccination API routes."""
from flask import Blueprint, jsonify, request
from pydantic import ValidationError

from app.models.vaccination import Vaccination
from app.repositories import vaccine_repository
from app.routes.access import ensure_can_access_patient_data, ensure_can_create_for_patient
from app.routes.auth import auth_required

vaccinations_bp = Blueprint('vaccinations_api', __name__)


@vaccinations_bp.route('/vaccinations', methods=['POST'])
@auth_required
def create_vaccination_endpoint():
    """Create a vaccination record.
    ---
    tags:
        - Vaccinations
    security:
        - BearerAuth: []
    requestBody:
        required: true
        content:
            application/json:
                schema:
                    $ref: '#/components/schemas/VaccinationCreateRequest'
    responses:
        201:
            description: Vaccination created
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/VaccinationResponse'
        400:
            description: Validation or payload error
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        401:
            description: Unauthorized
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        403:
            description: Forbidden
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
    """
    payload = request.get_json(silent=True) or {}
    patient_id = str(payload.get('patientId', ''))
    create_err = ensure_can_create_for_patient(patient_id)
    if create_err:
        return create_err

    vaccine_id = payload.get('vaccineId')
    if not vaccine_id or str(vaccine_id).startswith('mock-vac-'):
        count = len(vaccine_repository.find_by_patient_id(patient_id))
        payload['vaccineId'] = f"VAC-{count + 1:03d}"

    try:
        vaccination = Vaccination.model_validate(payload)
    except ValidationError as exc:
        return jsonify({'error': 'ValidationError', 'detail': str(exc)}), 400

    created = vaccine_repository.create(vaccination)
    return jsonify(created.model_dump(by_alias=True, mode='json')), 201


@vaccinations_bp.route('/vaccinations/<vaccination_id>', methods=['GET'])
@auth_required
def get_vaccination_by_id_endpoint(vaccination_id: str):
    """Get a vaccination by ID.
    ---
    tags:
        - Vaccinations
    security:
        - BearerAuth: []
    parameters:
        - in: path
          name: vaccination_id
          required: true
          schema:
            type: string
    responses:
        200:
            description: Vaccination found
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/VaccinationResponse'
        401:
            description: Unauthorized
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        403:
            description: Forbidden
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        404:
            description: Vaccination not found
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
    """
    vaccination = vaccine_repository.find_by_id(vaccination_id)
    if not vaccination:
        return jsonify({'error': 'NotFound'}), 404

    _, err = ensure_can_access_patient_data(str(vaccination.patientId))
    if err:
        return err

    return jsonify(vaccination.model_dump(by_alias=True, mode='json'))


@vaccinations_bp.route('/vaccinations', methods=['GET'])
@auth_required
def list_vaccinations_by_patient_endpoint():
    """List vaccinations by patient ID query parameter.
    ---
    tags:
        - Vaccinations
    security:
        - BearerAuth: []
    parameters:
        - in: query
          name: patientId
          required: true
          schema:
            type: string
    responses:
        200:
            description: Vaccination list
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/VaccinationResponseList'
        400:
            description: Missing patientId
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        401:
            description: Unauthorized
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        403:
            description: Forbidden
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
    """
    patient_id = request.args.get('patientId')
    if not patient_id:
        return jsonify({'error': 'MissingQueryParam', 'param': 'patientId'}), 400

    _, err = ensure_can_access_patient_data(patient_id)
    if err:
        return err

    vaccinations = vaccine_repository.find_by_patient_id(patient_id)
    return jsonify([v.model_dump(by_alias=True, mode='json') for v in vaccinations])


@vaccinations_bp.route('/vaccinations/<vaccination_id>', methods=['PATCH'])
@auth_required
def update_vaccination_endpoint(vaccination_id: str):
    """Update a vaccination record.
    ---
    tags:
        - Vaccinations
    security:
        - BearerAuth: []
    parameters:
        - in: path
          name: vaccination_id
          required: true
          schema:
            type: string
    requestBody:
        required: true
        content:
            application/json:
                schema:
                    $ref: '#/components/schemas/VaccinationUpdateRequest'
    responses:
        200:
            description: Vaccination updated
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/VaccinationResponse'
        400:
            description: No updatable fields
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        401:
            description: Unauthorized
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        403:
            description: Forbidden
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        404:
            description: Vaccination not found
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
    """
    existing = vaccine_repository.find_by_id(vaccination_id)
    if not existing:
        return jsonify({'error': 'NotFound'}), 404

    _, err = ensure_can_access_patient_data(str(existing.patientId))
    if err:
        return err

    updates = request.get_json(silent=True) or {}
    forbidden = {'_id', 'id', 'created_at', 'updated_at'}
    filtered_updates = {k: v for k, v in updates.items() if k not in forbidden}
    if not filtered_updates:
        return jsonify({'error': 'NoUpdatableFields'}), 400

    updated = vaccine_repository.update(vaccination_id, filtered_updates)
    if not updated:
        return jsonify({'error': 'NotFound'}), 404

    return jsonify(updated.model_dump(by_alias=True, mode='json'))
