import logging
import os
from datetime import datetime, timezone

from apscheduler.schedulers.background import BackgroundScheduler
from tinydb import Query

logger = logging.getLogger(__name__)


def _get_local_hour(tz_str: str | None) -> int:
    """Return the current hour (0-23) in the given IANA timezone, falling back to UTC."""
    try:
        if tz_str:
            from zoneinfo import ZoneInfo  # Python 3.9+
            local_now = datetime.now(ZoneInfo(tz_str))
            return local_now.hour
    except Exception:
        pass
    return datetime.now(timezone.utc).hour


def send_digests(app) -> None:
    """Hourly job: send the 9pm digest to every eligible user whose local time is 21."""
    if os.environ.get('DB_ENV') == 'e2e':
        return

    with app.app_context():
        try:
            from db.db import users_db, pending_confirmations_db, child_db, task_db, reward_db
            from utils.email_sender import send_digest_email
            from utils.digest_token import create_action_token, create_unsubscribe_token
            from flask import current_app

            frontend_url = current_app.config.get('FRONTEND_URL', 'https://localhost:5173')
            UserQ = Query()

            users = users_db.search(
                (UserQ.verified == True) & (UserQ.email_digest_enabled == True)
            )

            for user_dict in users:
                user_id = user_dict.get('id')
                user_email = user_dict.get('email')
                user_tz = user_dict.get('timezone')

                local_hour = _get_local_hour(user_tz)
                if local_hour != 21:
                    continue

                # Gather pending items for this user
                PendingQ = Query()
                pending_items = pending_confirmations_db.search(
                    (PendingQ.user_id == user_id) & (PendingQ.status == 'pending')
                )

                if not pending_items:
                    continue

                ChildQ = Query()
                TaskQ = Query()
                RewardQ = Query()
                items = []

                for p in pending_items:
                    child_id = p.get('child_id')
                    entity_id = p.get('entity_id')
                    entity_type = p.get('entity_type')

                    child_result = child_db.get(ChildQ.id == child_id)
                    if not child_result:
                        logger.warning(f'Digest: child {child_id} not found for pending item {p.get("id")} (user {user_id})')
                        continue
                    child_name = child_result.get('name')
                    if not child_name:
                        logger.warning(f'Digest: child {child_id} has no name (user {user_id})')
                        child_name = 'Unknown'

                    if entity_type == 'chore':
                        entity_result = task_db.get(
                            (TaskQ.id == entity_id) &
                            ((TaskQ.user_id == user_id) | (TaskQ.user_id == None))
                        )
                    else:
                        entity_result = reward_db.get(
                            (RewardQ.id == entity_id) &
                            ((RewardQ.user_id == user_id) | (RewardQ.user_id == None))
                        )

                    if not entity_result:
                        logger.warning(f'Digest: {entity_type} {entity_id} not found for pending item {p.get("id")} (user {user_id})')
                        continue
                    entity_name = entity_result.get('name')
                    if not entity_name:
                        logger.warning(f'Digest: {entity_type} {entity_id} has no name (user {user_id})')
                        entity_name = 'Unknown'

                    approve_token = create_action_token(
                        user_id=user_id,
                        child_id=child_id,
                        entity_id=entity_id,
                        entity_type=entity_type,
                        action='approve',
                    )
                    deny_token = create_action_token(
                        user_id=user_id,
                        child_id=child_id,
                        entity_id=entity_id,
                        entity_type=entity_type,
                        action='deny',
                    )

                    view_url = (
                        f"{frontend_url}/parent/{child_id}"
                        f"?scrollTo={entity_id}&entityType={entity_type}"
                    )
                    approve_url = f"{frontend_url}/api/digest-action/{approve_token.id}"
                    deny_url = f"{frontend_url}/api/digest-action/{deny_token.id}"

                    items.append({
                        'child_name': child_name,
                        'entity_name': entity_name,
                        'entity_type': entity_type,
                        'view_url': view_url,
                        'approve_url': approve_url,
                        'deny_url': deny_url,
                        'child_id': child_id,
                        'entity_id': entity_id,
                    })

                if not items:
                    continue

                unsubscribe_token = create_unsubscribe_token(user_id)
                try:
                    send_digest_email(user_email, items, unsubscribe_token)
                except Exception as e:
                    logger.error(f'Failed to send digest to {user_email}: {e}')

        except Exception as e:
            logger.error(f'Error in send_digests job: {e}')


def start_digest_scheduler(app) -> BackgroundScheduler:
    """Start the hourly digest scheduler. Returns the scheduler instance."""
    scheduler = BackgroundScheduler()
    scheduler.add_job(
        send_digests,
        'cron',
        minute=0,
        args=[app],
        id='digest_scheduler',
        replace_existing=True,
    )
    scheduler.start()
    logger.info('Digest scheduler started (hourly)')
    return scheduler
