"""Prescription API routes."""
from bson import ObjectId
from flask import Blueprint, jsonify, request
from pydantic import ValidationError

from app.db import Database
from app.models.prescription import Prescription
from app.repositories import prescription_repository
from app.routes.access import ensure_can_access_patient_data, ensure_can_create_for_patient
from app.routes.auth import auth_required


def _populate_medication(prescription_dict: dict) -> dict:
    """Populate medication details from the medications collection."""
    med_id = prescription_dict.get('medicationId')
    if med_id:
        med = Database.get_db().get_collection('medications').find_one(
            {'_id': ObjectId(str(med_id))}
        )
        if med:
            prescription_dict['medication'] = {
                '_id': str(med['_id']),
                'genericName': med.get('genericName', ''),
                'brandName': med.get('brandName', ''),
                'route': med.get('route', ''),
                'pharmClass': med.get('pharmClass', ''),
                'indications': med.get('indications', ''),
                'dosageAndAdministration': med.get('dosageAndAdministration', ''),
                'adverseReactions': med.get('adverseReactions', ''),
                'warnings': med.get('warnings', ''),
                'contraindications': med.get('contraindications', ''),
                'drugInteractions': med.get('drugInteractions', ''),
            }
    return prescription_dict

prescriptions_bp = Blueprint('prescriptions_api', __name__)


@prescriptions_bp.route('/medications/search', methods=['GET'])
@auth_required
def search_medications_endpoint():
    """Search for medications by name.
    ---
    tags:
        - Medications
    security:
        - BearerAuth: []
    parameters:
        - in: query
          name: q
          required: true
          schema:
            type: string
          description: Search query (minimum 2 characters)
    responses:
        200:
            description: List of matching medications
            content:
                application/json:
                    schema:
                        type: array
                        items:
                            type: object
                            properties:
                                _id:
                                    type: string
                                genericName:
                                    type: string
                                brandName:
                                    type: string
        401:
            description: Unauthorized
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
    """
    query = request.args.get('q', '')
    if len(query) < 2:
        return jsonify([])

    db = Database.get_db()
    results = db.get_collection('medications').find({
        '$or': [
            {'genericName': {'$regex': query, '$options': 'i'}},
            {'brandName': {'$regex': query, '$options': 'i'}}
        ]
    }).limit(10)

    return jsonify([
        {
            '_id': str(m['_id']),
            'genericName': m.get('genericName', ''),
            'brandName': m.get('brandName', ''),
        } for m in results
    ])


@prescriptions_bp.route('/prescriptions', methods=['POST'])
@auth_required
def create_prescription_endpoint():
    """Create a prescription.
    ---
    tags:
        - Prescriptions
    security:
        - BearerAuth: []
    requestBody:
        required: true
        content:
            application/json:
                schema:
                    $ref: '#/components/schemas/PrescriptionCreateRequest'
    responses:
        201:
            description: Prescription created
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/PrescriptionResponse'
        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:
        prescription = Prescription.model_validate(payload)
    except ValidationError as exc:
        return jsonify({'error': 'ValidationError', 'detail': str(exc)}), 400

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


@prescriptions_bp.route('/prescriptions/<prescription_id>', methods=['GET'])
@auth_required
def get_prescription_by_id_endpoint(prescription_id: str):
    """Get a prescription by ID.
    ---
    tags:
        - Prescriptions
    security:
        - BearerAuth: []
    parameters:
        - in: path
          name: prescription_id
          required: true
          schema:
            type: string
    responses:
        200:
            description: Prescription found
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/PrescriptionResponse'
        401:
            description: Unauthorized
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        403:
            description: Forbidden
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
        404:
            description: Prescription not found
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
    """
    prescription = prescription_repository.find_by_id(prescription_id)
    if not prescription:
        return jsonify({'error': 'NotFound'}), 404

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

    result = _populate_medication(prescription.model_dump(by_alias=True, mode='json'))
    return jsonify(result)


@prescriptions_bp.route('/prescriptions', methods=['GET'])
@auth_required
def list_prescriptions_by_patient_endpoint():
    """List prescriptions by patient ID query parameter.
    ---
    tags:
        - Prescriptions
    security:
        - BearerAuth: []
    parameters:
        - in: query
          name: patientId
          required: true
          schema:
            type: string
    responses:
        200:
            description: Prescription list
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/PrescriptionResponseList'
        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:
        prescriptions = prescription_repository.find_by_patient_id(patient_id)
    except ValueError as exc:
        return jsonify({'error': 'InvalidPatientId', 'detail': str(exc)}), 400

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


@prescriptions_bp.route('/prescriptions/<prescription_id>', methods=['PATCH'])
@auth_required
def update_prescription_endpoint(prescription_id: str):
    """Update a prescription record.
    ---
    tags:
        - Prescriptions
    security:
        - BearerAuth: []
    parameters:
        - in: path
          name: prescription_id
          required: true
          schema:
            type: string
    requestBody:
        required: true
        content:
            application/json:
                schema:
                    $ref: '#/components/schemas/PrescriptionUpdateRequest'
    responses:
        200:
            description: Prescription updated
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/PrescriptionResponse'
        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: Prescription not found
            content:
                application/json:
                    schema:
                        $ref: '#/components/schemas/ErrorResponse'
    """
    existing = prescription_repository.find_by_id(prescription_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 = prescription_repository.update(prescription_id, filtered_updates)
    if not updated:
        return jsonify({'error': 'NotFound'}), 404

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


@prescriptions_bp.route('/prescriptions/<prescription_id>', methods=['DELETE'])
@auth_required
def delete_prescription_endpoint(prescription_id: str):
    """Delete a prescription record.
    ---
    tags:
        - Prescriptions
    security:
        - BearerAuth: []
    parameters:
        - in: path
          name: prescription_id
          required: true
          schema:
            type: string
    responses:
        204:
            description: Prescription deleted
        401:
            description: Unauthorized
        403:
            description: Forbidden
        404:
            description: Prescription not found
    """
    existing = prescription_repository.find_by_id(prescription_id)
    if not existing:
        return jsonify({'error': 'NotFound'}), 404

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

    success = prescription_repository.delete(prescription_id)
    if not success:
        return jsonify({'error': 'NotFound'}), 404

    return '', 204
