from flask import Blueprint, request, jsonify
from tinydb import Query
from api.utils import get_validated_user_id, send_event_for_current_user
from api.error_codes import ErrorCodes
from db.db import child_db, pending_confirmations_db
from db.chore_schedules import get_schedule, upsert_schedule, delete_schedule
from db.task_extensions import get_extension, add_extension, delete_extension_for_child_task
from models.chore_schedule import ChoreSchedule
from models.task_extension import TaskExtension
from events.types.event import Event
from events.types.event_types import EventType
from events.types.chore_schedule_modified import ChoreScheduleModified
from events.types.chore_time_extended import ChoreTimeExtended
from events.types.child_chore_confirmation import ChildChoreConfirmation
import logging

chore_schedule_api = Blueprint('chore_schedule_api', __name__)
logger = logging.getLogger(__name__)


def _validate_child(child_id: str, user_id: str):
    """Return child dict if found and owned by user, else None."""
    ChildQuery = Query()
    result = child_db.search((ChildQuery.id == child_id) & (ChildQuery.user_id == user_id))
    return result[0] if result else None


@chore_schedule_api.route('/child/<child_id>/task/<task_id>/schedule', methods=['GET'])
def get_chore_schedule(child_id, task_id):
    user_id = get_validated_user_id()
    if not user_id:
        return jsonify({'error': 'Unauthorized', 'code': ErrorCodes.UNAUTHORIZED}), 401

    if not _validate_child(child_id, user_id):
        return jsonify({'error': 'Child not found', 'code': ErrorCodes.CHILD_NOT_FOUND}), 404

    schedule = get_schedule(child_id, task_id)
    if not schedule:
        return jsonify({'error': 'Schedule not found'}), 404

    return jsonify(schedule.to_dict()), 200


@chore_schedule_api.route('/child/<child_id>/task/<task_id>/schedule', methods=['PUT'])
def set_chore_schedule(child_id, task_id):
    user_id = get_validated_user_id()
    if not user_id:
        return jsonify({'error': 'Unauthorized', 'code': ErrorCodes.UNAUTHORIZED}), 401

    if not _validate_child(child_id, user_id):
        return jsonify({'error': 'Child not found', 'code': ErrorCodes.CHILD_NOT_FOUND}), 404

    data = request.get_json() or {}
    mode = data.get('mode')
    if mode not in ('days', 'interval'):
        return jsonify({'error': 'mode must be "days" or "interval"', 'code': ErrorCodes.INVALID_VALUE}), 400

    enabled = data.get('enabled', True)
    if not isinstance(enabled, bool):
        return jsonify({'error': 'enabled must be a boolean', 'code': ErrorCodes.INVALID_VALUE}), 400

    if mode == 'days':
        day_configs = data.get('day_configs', [])
        if not isinstance(day_configs, list):
            return jsonify({'error': 'day_configs must be a list', 'code': ErrorCodes.INVALID_VALUE}), 400
        default_hour = data.get('default_hour', 8)
        default_minute = data.get('default_minute', 0)
        default_has_deadline = data.get('default_has_deadline', True)
        schedule = ChoreSchedule(
            child_id=child_id,
            task_id=task_id,
            mode='days',
            day_configs=day_configs,
            default_hour=default_hour,
            default_minute=default_minute,
            default_has_deadline=default_has_deadline,
            enabled=enabled,
        )
    else:
        interval_days = data.get('interval_days', 2)
        anchor_date = data.get('anchor_date', '')
        interval_has_deadline = data.get('interval_has_deadline', True)
        interval_hour = data.get('interval_hour', 0)
        interval_minute = data.get('interval_minute', 0)
        if not isinstance(interval_days, int) or not (1 <= interval_days <= 7):
            return jsonify({'error': 'interval_days must be an integer between 1 and 7', 'code': ErrorCodes.INVALID_VALUE}), 400
        if not isinstance(anchor_date, str):
            return jsonify({'error': 'anchor_date must be a string', 'code': ErrorCodes.INVALID_VALUE}), 400
        if not isinstance(interval_has_deadline, bool):
            return jsonify({'error': 'interval_has_deadline must be a boolean', 'code': ErrorCodes.INVALID_VALUE}), 400
        schedule = ChoreSchedule(
            child_id=child_id,
            task_id=task_id,
            mode='interval',
            interval_days=interval_days,
            anchor_date=anchor_date,
            interval_has_deadline=interval_has_deadline,
            interval_hour=interval_hour,
            interval_minute=interval_minute,
            enabled=enabled,
        )

    delete_extension_for_child_task(child_id, task_id)
    upsert_schedule(schedule)

    # Reset pending chore confirmations when schedule changes (completed chores stay)
    PendingQuery = Query()
    pending_chores = pending_confirmations_db.search(
        (PendingQuery.child_id == child_id) & (PendingQuery.entity_id == task_id) &
        (PendingQuery.entity_type == 'chore') & (PendingQuery.status == 'pending')
    )
    for pc in pending_chores:
        pending_confirmations_db.remove(
            (PendingQuery.child_id == child_id) & (PendingQuery.entity_id == task_id) &
            (PendingQuery.entity_type == 'chore') & (PendingQuery.status == 'pending')
        )
        send_event_for_current_user(Event(EventType.CHILD_CHORE_CONFIRMATION.value,
            ChildChoreConfirmation(child_id, task_id, ChildChoreConfirmation.OPERATION_RESET)))

    send_event_for_current_user(Event(
        EventType.CHORE_SCHEDULE_MODIFIED.value,
        ChoreScheduleModified(child_id, task_id, ChoreScheduleModified.OPERATION_SET)
    ))

    return jsonify(schedule.to_dict()), 200


@chore_schedule_api.route('/child/<child_id>/task/<task_id>/schedule', methods=['DELETE'])
def delete_chore_schedule(child_id, task_id):
    user_id = get_validated_user_id()
    if not user_id:
        return jsonify({'error': 'Unauthorized', 'code': ErrorCodes.UNAUTHORIZED}), 401

    if not _validate_child(child_id, user_id):
        return jsonify({'error': 'Child not found', 'code': ErrorCodes.CHILD_NOT_FOUND}), 404

    removed = delete_schedule(child_id, task_id)
    if not removed:
        return jsonify({'error': 'Schedule not found'}), 404

    send_event_for_current_user(Event(
        EventType.CHORE_SCHEDULE_MODIFIED.value,
        ChoreScheduleModified(child_id, task_id, ChoreScheduleModified.OPERATION_DELETED)
    ))

    return jsonify({'message': 'Schedule deleted'}), 200


@chore_schedule_api.route('/child/<child_id>/task/<task_id>/extend', methods=['POST'])
def extend_chore_time(child_id, task_id):
    user_id = get_validated_user_id()
    if not user_id:
        return jsonify({'error': 'Unauthorized', 'code': ErrorCodes.UNAUTHORIZED}), 401

    if not _validate_child(child_id, user_id):
        return jsonify({'error': 'Child not found', 'code': ErrorCodes.CHILD_NOT_FOUND}), 404

    data = request.get_json() or {}
    date = data.get('date')
    if not date or not isinstance(date, str):
        return jsonify({'error': 'date is required (ISO date string)', 'code': ErrorCodes.MISSING_FIELD}), 400

    # 409 if already extended for this exact date
    existing = get_extension(child_id, task_id, date)
    if existing:
        return jsonify({'error': 'Chore already extended for this date', 'code': 'ALREADY_EXTENDED'}), 409

    # Clear any prior extension for this child+task before inserting the new one
    # so stale records from previous dates do not accumulate.
    delete_extension_for_child_task(child_id, task_id)
    extension = TaskExtension(child_id=child_id, task_id=task_id, date=date)
    add_extension(extension)

    send_event_for_current_user(Event(
        EventType.CHORE_TIME_EXTENDED.value,
        ChoreTimeExtended(child_id, task_id)
    ))

    return jsonify(extension.to_dict()), 200
