from flask import Blueprint, request, jsonify
from tinydb import Query

from api.utils import send_event_for_current_user, get_validated_user_id
from db.db import routine_db, child_db, pending_confirmations_db
from db.child_overrides import delete_overrides_for_entity
from db.routine_items import delete_for_routine
from db.routine_schedules import delete_schedules_for_routine
from db.routine_extensions import delete_extensions_for_routine
from events.types.event import Event
from events.types.event_types import EventType
from events.types.routine_modified import RoutineModified
from events.types.child_routines_set import ChildRoutinesSet
from models.routine import Routine

routine_api = Blueprint('routine_api', __name__)


@routine_api.route('/routine/add', methods=['PUT'])
def add_routine():
    user_id = get_validated_user_id()
    if not user_id:
        return jsonify({'error': 'Unauthorized', 'code': 'UNAUTHORIZED'}), 401

    data = request.get_json() or {}
    name = data.get('name')
    points = data.get('points')
    image = data.get('image_id', '')

    if not name or points is None:
        return jsonify({'error': 'Name and points are required'}), 400

    routine = Routine(name=name, points=points, image_id=image, user_id=user_id)
    routine_db.insert(routine.to_dict())

    send_event_for_current_user(
        Event(EventType.ROUTINE_MODIFIED.value, RoutineModified(routine.id, RoutineModified.OPERATION_ADD))
    )
    return jsonify({'message': f'Routine {name} added.', 'routine': routine.to_dict()}), 201


@routine_api.route('/routine/<id>', methods=['GET'])
def get_routine(id):
    user_id = get_validated_user_id()
    if not user_id:
        return jsonify({'error': 'Unauthorized', 'code': 'UNAUTHORIZED'}), 401

    q = Query()
    result = routine_db.search((q.id == id) & ((q.user_id == user_id) | (q.user_id == None)))
    if not result:
        return jsonify({'error': 'Routine not found'}), 404

    return jsonify(result[0]), 200


@routine_api.route('/routine/list', methods=['GET'])
def list_routines():
    user_id = get_validated_user_id()
    if not user_id:
        return jsonify({'error': 'Unauthorized', 'code': 'UNAUTHORIZED'}), 401

    ids_param = request.args.get('ids')
    q = Query()
    routines = routine_db.search((q.user_id == user_id) | (q.user_id == None))

    if ids_param is not None:
        if ids_param.strip() == '':
            routines = []
        else:
            ids = set(ids_param.split(','))
            routines = [routine for routine in routines if routine.get('id') in ids]

    user_routines = {r['name'].strip().lower(): r for r in routines if r.get('user_id') == user_id}
    filtered_routines = []
    for routine in routines:
        if routine.get('user_id') is None and routine['name'].strip().lower() in user_routines:
            continue
        filtered_routines.append(routine)

    user_created = sorted(
        [r for r in filtered_routines if r.get('user_id') == user_id],
        key=lambda x: x['name'].lower(),
    )
    default_items = sorted(
        [r for r in filtered_routines if r.get('user_id') is None],
        key=lambda x: x['name'].lower(),
    )

    return jsonify({'routines': user_created + default_items}), 200


@routine_api.route('/routine/<id>/edit', methods=['PUT'])
def edit_routine(id):
    user_id = get_validated_user_id()
    if not user_id:
        return jsonify({'error': 'Unauthorized', 'code': 'UNAUTHORIZED'}), 401

    q = Query()
    existing = routine_db.get((q.id == id) & ((q.user_id == user_id) | (q.user_id == None)))
    if not existing:
        return jsonify({'error': 'Routine not found'}), 404

    routine = Routine.from_dict(existing)
    data = request.get_json(force=True) or {}
    is_dirty = False

    if 'name' in data:
        name = data.get('name', '').strip()
        if not name:
            return jsonify({'error': 'Name cannot be empty'}), 400
        routine.name = name
        is_dirty = True

    if 'points' in data:
        points = data.get('points')
        if not isinstance(points, int) or points <= 0:
            return jsonify({'error': 'Points must be a positive integer'}), 400
        routine.points = points
        is_dirty = True

    if 'image_id' in data:
        routine.image_id = data.get('image_id', '')
        is_dirty = True

    if not is_dirty:
        return jsonify({'error': 'No valid fields to update'}), 400

    if routine.user_id is None:
        new_routine = Routine(name=routine.name, points=routine.points, image_id=routine.image_id, user_id=user_id)
        routine_db.insert(new_routine.to_dict())
        send_event_for_current_user(
            Event(EventType.ROUTINE_MODIFIED.value, RoutineModified(new_routine.id, RoutineModified.OPERATION_ADD))
        )
        return jsonify(new_routine.to_dict()), 200

    routine_db.update(routine.to_dict(), q.id == id)
    send_event_for_current_user(
        Event(EventType.ROUTINE_MODIFIED.value, RoutineModified(id, RoutineModified.OPERATION_EDIT))
    )
    return jsonify(routine.to_dict()), 200


@routine_api.route('/routine/<id>', methods=['DELETE'])
def delete_routine(id):
    user_id = get_validated_user_id()
    if not user_id:
        return jsonify({'error': 'Unauthorized', 'code': 'UNAUTHORIZED'}), 401

    q = Query()
    routine = routine_db.get(q.id == id)
    if not routine:
        return jsonify({'error': 'Routine not found'}), 404

    if routine.get('user_id') is None:
        return jsonify({'error': 'System routines cannot be deleted.'}), 403

    removed = routine_db.remove((q.id == id) & (q.user_id == user_id))
    if not removed:
        return jsonify({'error': 'Routine not found'}), 404

    delete_overrides_for_entity(id)
    delete_for_routine(id)
    delete_schedules_for_routine(id)
    delete_extensions_for_routine(id)

    pending_q = Query()
    pending_confirmations_db.remove(
        (pending_q.entity_id == id) & (pending_q.entity_type == 'routine') & (pending_q.user_id == user_id)
    )

    child_q = Query()
    children = child_db.search(child_q.user_id == user_id)
    for child in children:
        routine_ids = child.get('routines', [])
        if id in routine_ids:
            routine_ids = [rid for rid in routine_ids if rid != id]
            child_db.update({'routines': routine_ids}, child_q.id == child.get('id'))
            send_event_for_current_user(
                Event(EventType.CHILD_ROUTINES_SET.value, ChildRoutinesSet(child.get('id'), routine_ids))
            )

    send_event_for_current_user(
        Event(EventType.ROUTINE_MODIFIED.value, RoutineModified(id, RoutineModified.OPERATION_DELETE))
    )
    return jsonify({'message': f'Routine {id} deleted.'}), 200
