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

from app.models.graph_preset import GraphPreset
from app.repositories import graph_preset_repository
from app.routes.access import ensure_can_access_patient_data, ensure_can_create_for_patient
from app.routes.auth import auth_required

graph_presets_bp = Blueprint('graph_presets_api', __name__)


@graph_presets_bp.route('/graph-presets', methods=['POST'])
@auth_required
def create_graph_preset_endpoint():
    """Create and persist a graph preset for a patient.
    ---
    tags:
        - Graph Presets
    security:
        - BearerAuth: []
    requestBody:
        required: true
        content:
            application/json:
                schema:
                    $ref: '#/components/schemas/GraphPreset'
    responses:
        201:
            description: Graph preset created
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/GraphPreset'
        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:
        preset = GraphPreset.model_validate(payload)
    except ValidationError as exc:
        return jsonify({'error': 'ValidationError', 'detail': str(exc)}), 400

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


@graph_presets_bp.route('/graph-presets', methods=['GET'])
@auth_required
def list_graph_presets_endpoint():
    """List graph presets for a patient.
    ---
    tags:
        - Graph Presets
    security:
        - BearerAuth: []
    parameters:
        - in: query
          name: patientId
          required: true
          schema:
            type: string
          description: Patient ID whose presets should be returned
    responses:
        200:
            description: Preset list
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/GraphPresetListResponse'
        400:
            description: Missing or invalid patient ID
            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', '')
    _, access_err = ensure_can_access_patient_data(patient_id)
    if access_err:
        return access_err

    try:
        presets = graph_preset_repository.find_by_patient_id(patient_id)
    except ValueError as exc:
        return jsonify({'error': 'ValidationError', 'detail': str(exc)}), 400

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


@graph_presets_bp.route('/graph-presets/<preset_id>', methods=['GET'])
@auth_required
def get_graph_preset_endpoint(preset_id: str):
    """Get a single graph preset by ID.
    ---
    tags:
        - Graph Presets
    security:
        - BearerAuth: []
    parameters:
        - in: path
          name: preset_id
          required: true
          schema:
            type: string
          description: Graph preset ID
    responses:
        200:
            description: Graph preset found
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/GraphPreset'
        401:
            description: Unauthorized
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        403:
            description: Forbidden
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        404:
            description: Graph preset not found
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
    """
    preset = graph_preset_repository.find_by_id(preset_id)
    if not preset:
        return jsonify({'error': 'GraphPresetNotFound'}), 404

    _, access_err = ensure_can_access_patient_data(str(preset.patientId))
    if access_err:
        return access_err

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


@graph_presets_bp.route('/graph-presets/<preset_id>', methods=['PUT'])
@auth_required
def update_graph_preset_endpoint(preset_id: str):
    """Update an existing graph preset by ID.
    ---
    tags:
        - Graph Presets
    security:
        - BearerAuth: []
    parameters:
        - in: path
          name: preset_id
          required: true
          schema:
            type: string
          description: Graph preset ID
    requestBody:
        required: true
        content:
            application/json:
                schema:
                    $ref: '#/components/schemas/GraphPreset'
    responses:
        200:
            description: Graph preset updated
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/GraphPreset'
        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'
        404:
            description: Graph preset not found
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
    """
    existing = graph_preset_repository.find_by_id(preset_id)
    if not existing:
        return jsonify({'error': 'GraphPresetNotFound'}), 404

    update_err = ensure_can_create_for_patient(str(existing.patientId))
    if update_err:
        return update_err

    payload = request.get_json(silent=True) or {}
    payload.pop('_id', None)
    payload.pop('patientId', None)

    try:
        updated = graph_preset_repository.update(preset_id, payload)
    except ValueError as exc:
        return jsonify({'error': 'ValidationError', 'detail': str(exc)}), 400

    if not updated:
        return jsonify({'error': 'GraphPresetNotFound'}), 404

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


@graph_presets_bp.route('/graph-presets/<preset_id>', methods=['DELETE'])
@auth_required
def delete_graph_preset_endpoint(preset_id: str):
    """Delete a graph preset by ID.
    ---
    tags:
        - Graph Presets
    security:
        - BearerAuth: []
    parameters:
        - in: path
          name: preset_id
          required: true
          schema:
            type: string
          description: Graph preset ID
    responses:
        200:
            description: Graph preset deleted
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/GraphPresetDeleteResponse'
        401:
            description: Unauthorized
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        403:
            description: Forbidden
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        404:
            description: Graph preset not found
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
    """
    existing = graph_preset_repository.find_by_id(preset_id)
    if not existing:
        return jsonify({'error': 'GraphPresetNotFound'}), 404

    delete_err = ensure_can_create_for_patient(str(existing.patientId))
    if delete_err:
        return delete_err

    deleted = graph_preset_repository.delete(preset_id)
    if not deleted:
        return jsonify({'error': 'GraphPresetNotFound'}), 404

    return jsonify({'ok': True})


@graph_presets_bp.route('/graph-presets', methods=['DELETE'])
@auth_required
def delete_graph_presets_by_patient_endpoint():
    """Delete all graph presets for a patient.
    ---
    tags:
        - Graph Presets
    security:
        - BearerAuth: []
    parameters:
        - in: query
          name: patientId
          required: true
          schema:
            type: string
          description: Patient ID whose presets should be deleted
    responses:
        200:
            description: Graph presets deleted
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/BulkDeleteResponse'
        400:
            description: Missing or invalid patient ID
            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

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

    try:
        deleted_count = graph_preset_repository.delete_by_patient_id(patient_id)
    except ValueError as exc:
        return jsonify({'error': 'InvalidPatientId', 'detail': str(exc)}), 400

    return jsonify({'ok': True, 'deletedCount': deleted_count})
