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

from app.models.operation import Operation
from app.repositories import operation_repository
from app.routes.access import ensure_can_access_patient_data, ensure_can_create_for_patient
from app.routes.auth import auth_required

operations_bp = Blueprint('operations_api', __name__)


@operations_bp.route('/operations', methods=['POST'])
@auth_required
def create_operation_endpoint():
    """Create an operation.
    ---
    tags:
        - Operations
    security:
        - BearerAuth: []
    requestBody:
        required: true
        content:
            application/json:
                schema:
                    $ref: '#/components/schemas/OperationCreateRequest'
    responses:
        201:
            description: Operation created
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/OperationResponse'
        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

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

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


@operations_bp.route('/operations/<operation_id>', methods=['GET'])
@auth_required
def get_operation_by_id_endpoint(operation_id: str):
    """Get an operation by ID.
    ---
    tags:
        - Operations
    security:
        - BearerAuth: []
    parameters:
        - in: path
          name: operation_id
          required: true
          schema:
            type: string
    responses:
        200:
            description: Operation found
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/OperationResponse'
        401:
            description: Unauthorized
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        403:
            description: Forbidden
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        404:
            description: Operation not found
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
    """
    operation = operation_repository.find_by_id(operation_id)
    if not operation:
        return jsonify({'error': 'NotFound'}), 404

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

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


@operations_bp.route('/operations', methods=['GET'])
@auth_required
def list_operations_by_patient_endpoint():
    """List operations by patient ID query parameter.
    ---
    tags:
        - Operations
    security:
        - BearerAuth: []
    parameters:
        - in: query
          name: patientId
          required: true
          schema:
            type: string
    responses:
        200:
            description: Operation list
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/OperationResponseList'
        400:
            description: Missing or invalid 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

    try:
        operations = operation_repository.find_by_patient_id(patient_id)
    except ValueError as exc:
        return jsonify({'error': 'InvalidPatientId', 'detail': str(exc)}), 400

    return jsonify([o.model_dump(by_alias=True, mode='json') for o in operations])


@operations_bp.route('/operations/<operation_id>', methods=['PATCH'])
@auth_required
def update_operation_endpoint(operation_id: str):
    """Update an operation record.
    ---
    tags:
        - Operations
    security:
        - BearerAuth: []
    parameters:
        - in: path
          name: operation_id
          required: true
          schema:
            type: string
    requestBody:
        required: true
        content:
            application/json:
                schema:
                    $ref: '#/components/schemas/OperationUpdateRequest'
    responses:
        200:
            description: Operation updated
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/OperationResponse'
        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: Operation not found
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
    """
    existing = operation_repository.find_by_id(operation_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 = operation_repository.update(operation_id, filtered_updates)
    if not updated:
        return jsonify({'error': 'NotFound'}), 404

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