"""/api/cron — reads echo-core/cron/jobs.json (flat schema)."""
import json
from datetime import datetime

import constants


def _parse_cron_time(expr):
    """Extract a display-time string from a cron expression.

    Echo-core cron strings are already Bucharest local time (Lane B
    scheduler sets tz=Europe/Bucharest), so NO UTC→local conversion.
    """
    parts = expr.split()
    if len(parts) < 2:
        return expr[:15]
    minute, hour = parts[0], parts[1]
    if minute.isdigit() and (hour.isdigit() or '-' in hour):
        if '-' in hour:
            hour = hour.split('-')[0]
        try:
            return f"{int(hour):02d}:{int(minute):02d}"
        except ValueError:
            return expr[:15]
    return expr[:15]


def _iso_to_epoch_ms(iso_str):
    """Convert an ISO 8601 datetime string to epoch ms. Returns 0 on failure."""
    if not iso_str:
        return 0
    try:
        dt = datetime.fromisoformat(iso_str.replace('Z', '+00:00'))
        return int(dt.timestamp() * 1000)
    except (ValueError, TypeError):
        return 0


class CronHandlers:
    """Mixin for /api/cron."""

    def handle_cron_status(self):
        """Get enabled cron jobs from echo-core/cron/jobs.json (flat schema).

        Output shape preserved for the frontend: id, name, time, schedule,
        ranToday, lastStatus, lastRunAtMs, nextRunAtMs.
        """
        try:
            jobs_file = constants.BASE_DIR / 'cron' / 'jobs.json'
            if not jobs_file.exists():
                self.send_json({'jobs': [], 'error': 'No jobs file found'})
                return

            all_jobs = json.loads(jobs_file.read_text())
            if not isinstance(all_jobs, list):
                self.send_json({'jobs': [], 'error': 'Unexpected jobs.json shape'})
                return

            today_start = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
            today_start_ms = today_start.timestamp() * 1000

            jobs = []
            for job in all_jobs:
                if not job.get('enabled', False):
                    continue

                name = job.get('name', '')
                expr = job.get('cron', '')
                last_run_iso = job.get('last_run')
                next_run_iso = job.get('next_run')
                last_status = job.get('last_status', 'unknown')

                last_run_ms = _iso_to_epoch_ms(last_run_iso)
                next_run_ms = _iso_to_epoch_ms(next_run_iso) or None
                ran_today = last_run_ms >= today_start_ms

                jobs.append({
                    'id': name,                 # echo-core has no separate id; use name
                    'name': name,
                    'time': _parse_cron_time(expr),
                    'schedule': expr,
                    'ranToday': ran_today,
                    'lastStatus': last_status if ran_today else None,
                    'lastRunAtMs': last_run_ms,
                    'nextRunAtMs': next_run_ms,
                })

            jobs.sort(key=lambda j: j['time'])
            self.send_json({
                'jobs': jobs,
                'total': len(jobs),
                'ranToday': sum(1 for j in jobs if j['ranToday']),
            })
        except Exception as e:
            self.send_json({'error': str(e)}, 500)
