import os

from celery import Celery
from celery.schedules import crontab

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.development")

app = Celery("config")
app.config_from_object("django.conf:settings", namespace="CELERY")
app.autodiscover_tasks()

app.conf.beat_schedule = {
    "send-pending-notifications": {
        "task": "apps.core.tasks.run_send_pending_notifications",
        "schedule": crontab(minute="*/15"),
    },
    "rims-grant-deadline-reminders": {
        "task": "apps.rims.grants.tasks.remind_grant_call_deadlines",
        "schedule": crontab(hour=7, minute=0),
    },
    "rims-close-expired-calls": {
        "task": "apps.rims.grants.tasks.close_expired_calls",
        "schedule": crontab(minute="*/5"),
    },
    "rims-award-acknowledgement-reminders": {
        "task": "apps.rims.grants.tasks.remind_award_acknowledgements",
        "schedule": crontab(hour=7, minute=30),
    },
    "rims-review-deadline-reminders": {
        "task": "apps.rims.grants.tasks.remind_overdue_reviews",
        "schedule": crontab(hour=8, minute=0),
    },
    "rims-milestone-health": {
        "task": "apps.rims.projects.tasks.flag_overdue_milestones",
        "schedule": crontab(hour=6, minute=30),
    },
    "rims-milestone-upcoming-reminders": {
        "task": "apps.rims.projects.tasks.remind_upcoming_milestone_reports",
        "schedule": crontab(hour=7, minute=15),
    },
    # PRD §5.1 FRFA-CO003 — auto-trigger close-out at award end-date.
    "rims-expire-awards": {
        "task": "apps.rims.grants.tasks.expire_awards",
        "schedule": crontab(hour=3, minute=0),
    },
    # PRD §5.1 FRFA-AA009 — chase awardees who haven't returned a signed agreement.
    "rims-chase-agreements": {
        "task": "apps.rims.grants.tasks.chase_agreements",
        "schedule": crontab(hour=8, minute=30),
    },
    # PRD §5.1 FRFA-CO011 — chase awardees in close-out for missing final reports.
    "rims-remind-closeout-reports": {
        "task": "apps.rims.grants.tasks.remind_closeout_reports",
        "schedule": crontab(hour=9, minute=0),
    },
    # PRD §5.1 FRFA-CO015/016/017 — daily archive sweep for closed awards once
    # their funding-type-specific retention window elapses.
    "rims-archive-closed-awards": {
        "task": "apps.rims.grants.tasks.archive_closed_awards",
        "schedule": crontab(hour=3, minute=15),
    },
    # PRD §5.4 NFRFM004 — daily variance alert scan.
    "rims-finance-variance-scan": {
        "task": "apps.rims.finance.tasks.scan_budget_variances",
        "schedule": crontab(hour=6, minute=0),
    },
    # PRD §5.4 FRFM26 — daily payment-due reminder sweep.
    "rims-finance-payment-due-reminders": {
        "task": "apps.rims.finance.tasks.remind_payment_due",
        "schedule": crontab(hour=6, minute=15),
    },
    # PRD §5.4 FRFM027 — monthly rolling-budget reforecast (1st of each month, 04:30).
    "rims-finance-reforecast-monthly": {
        "task": "apps.rims.finance.tasks.recompute_reforecasts",
        "schedule": crontab(hour=4, minute=30, day_of_month="1"),
    },
    # PRD §5.4 FRFM043 — payment-retry queue sweep (every 2 hours).
    "rims-finance-payment-retry-sweep": {
        "task": "apps.rims.finance.tasks.process_payment_retry_queue",
        "schedule": crontab(minute=0, hour="*/2"),
    },
    # PRD §5.4 FRFM046/049 — daily GL re-validation + posting recovery (05:00).
    "rims-finance-gl-reconcile": {
        "task": "apps.rims.finance.tasks.revalidate_gl_entries",
        "schedule": crontab(hour=5, minute=0),
    },
    # P1 (assessment §3 #10) — daily MOU expiry sweep.
    "rims-ops-expire-mous": {
        "task": "apps.rims.operations.tasks.expire_mous",
        "schedule": crontab(hour=3, minute=30),
    },
    # P1 (assessment §4 N7) — 30-day pre-expiry renewal reminder.
    "rims-ops-mou-renewal-reminders": {
        "task": "apps.rims.operations.tasks.remind_mou_renewals",
        "schedule": crontab(hour=9, minute=30),
    },
    # P1 (assessment §3 #11) — auto-complete past-due interviews so reviewer
    # assignment gates don't wait on a manual flag.
    "rims-grants-auto-complete-interviews": {
        "task": "apps.rims.grants.tasks.auto_complete_interviews",
        "schedule": crontab(minute="*/15"),
    },
    "careers-expire-job-listings": {
        "task": "apps.alumni.careers.tasks.expire_job_listings",
        "schedule": crontab(hour=2, minute=0),
    },
    # Pull Moodle learning outcomes into MEL hourly (no-op until MOODLE_WS_TOKEN set).
    "mel-pull-moodle-outcomes": {
        "task": "apps.mel.tracking.pull_moodle_outcomes",
        "schedule": crontab(minute=15),
    },
    # IILMP→Moodle role projection reconcile (assign + demote) — catches role
    # changes made in IILMP after a user's first SSO login. Login-time sync is
    # assign-only. No-op until MOODLE_WS_TOKEN is set.
    "core-sync-moodle-roles-nightly": {
        "task": "apps.core.tasks.run_sync_moodle_roles",
        "schedule": crontab(hour=4, minute=15),
    },
    # REP LMS beat tasks (integration-outbox drain, recommendations, MEL payload
    # dump, enrolment-growth snapshot, live-session notifications/recording sync,
    # video-transcode watchdog) were removed with the REP platform. Moodle
    # outcome ingest is scheduled via apps.mel.tracking.pull_moodle_outcomes.
    "alumni-orcid-weekly": {
        "task": "apps.alumni.tasks.sync_orcid_for_all_profiles",
        "schedule": crontab(day_of_week="sun", hour=2, minute=0),
    },
    "alumni-impact-snapshot-monthly": {
        "task": "apps.alumni.tasks.snapshot_impact_metrics",
        "schedule": crontab(day_of_month="1", hour=1, minute=0),
    },
    "alumni-event-reminders": {
        "task": "apps.alumni.tasks.send_event_reminders",
        "schedule": crontab(minute="*/15"),
    },
    "alumni-group-event-nudges": {
        "task": "apps.alumni.tasks.send_group_event_nudges",
        "schedule": crontab(minute="5", hour="*/3"),  # every 3h, offset by 5min
    },
    "alumni-spotlight-digest": {
        "task": "apps.alumni.tasks.send_spotlight_digest",
        "schedule": crontab(hour=7, minute=0, day_of_week="mon"),  # Monday 07:00 UTC
    },
    # §4.3.5 FRALU — fire officer broadcasts whose scheduled_for has arrived
    # (compose form arms SCHEDULED; this beat tick delivers them).
    "alumni-send-scheduled-broadcasts": {
        "task": "apps.alumni.tasks.send_due_scheduled_broadcasts",
        "schedule": crontab(minute="*/5"),
    },
    # §4.3.5 FRALU — refresh alumni semantic-search vectors weekly so the
    # /alumni/?mode=semantic path ranks by intent (falls back to FTS until run).
    "alumni-embedding-backfill-weekly": {
        "task": "apps.alumni.tasks.backfill_alumni_embeddings",
        "schedule": crontab(day_of_week="sun", hour=3, minute=0),  # Sunday 03:00 UTC
    },
    # FRREP-DCI012 — fetch inbound mail submissions for the Repository.
    # No-op when REPO_INBOUND_IMAP_HOST is empty (dev / staging default).
    "repo-poll-inbox": {
        "task": "apps.repository.integration.tasks.poll_repository_inbox",
        "schedule": crontab(minute="*/5"),
    },
    # FRREP-DCI004 — sweep abandoned + expired resumable upload sessions.
    "repo-cleanup-resumable-uploads": {
        "task": "apps.repository.documents.tasks.cleanup_resumable_uploads",
        "schedule": crontab(minute=15),
    },
    # FRREP-VL006 — daily retention-policy enforcement sweep (archive/flag/
    # withdraw + admin escalation on documents past their collection's
    # retention window). Built and tested but was never scheduled.
    "repo-enforce-retention-policies": {
        "task": "apps.repository.documents.tasks.enforce_retention_policies",
        "schedule": crontab(hour=3, minute=45),
    },
    # FRREP-INT integration outbox — deliver queued cross-app events (REP OER
    # broken-link notices, MEL feed, SME-Hub) that receivers only enqueue.
    "repo-dispatch-outbox": {
        "task": "apps.repository.documents.tasks.dispatch_outbox_pending",
        "schedule": crontab(minute="*/10"),
    },
    # FRREP-QA008 — escalate QA reviews sitting in the queue past their SLA.
    "repo-escalate-overdue-qa-reviews": {
        "task": "apps.repository.documents.tasks.escalate_overdue_qa_reviews",
        "schedule": crontab(hour=8, minute=45),
    },
    # FRREP-COL006 — remind collaborators (and the document owner) of overdue
    # review tasks.
    "repo-review-task-reminders": {
        "task": "apps.repository.documents.tasks.send_review_task_reminders",
        "schedule": crontab(hour=9, minute=15),
    },
    # FRREP-SR010 — deliver saved-search alert digests.
    "repo-saved-search-alerts": {
        "task": "apps.repository.documents.tasks.dispatch_saved_search_alerts",
        "schedule": crontab(hour=6, minute=45),
    },
    # FRREP-AR012 — push Repository indicators to the M&E module daily.
    "repo-mel-indicator-push": {
        "task": "apps.repository.analytics.tasks.mel_indicator_daily_push",
        "schedule": crontab(hour=5, minute=30),
    },
    # FRREP-AR010 — weekly research-trend clustering refresh (KMeans + LLM
    # labelling is expensive; run off-peak).
    "repo-refresh-research-trends": {
        "task": "apps.repository.analytics.tasks.refresh_research_trends",
        "schedule": crontab(day_of_week="sun", hour=2, minute=30),
    },
    # Weekly per-collection/document usage rollup for analytics dashboards.
    "repo-weekly-analytics-rollup": {
        "task": "apps.repository.analytics.tasks.weekly_analytics_rollup",
        "schedule": crontab(day_of_week="sun", hour=1, minute=30),
    },
    # FRREP-TS007 — retry FAILED alumni handoffs hourly.
    "careers-retry-alumni-handoffs": {
        "task": "apps.alumni.careers.tasks.retry_pending_alumni_handoffs",
        "schedule": crontab(minute=25),
    },
    # REP cert-email retry, waitlist sweep, enrolment-expiry sweep, and mentorship
    # auto-flip beats were removed with the REP LMS.
    # FRSME-MEI012 — nightly stall sweep + MEL-officer notification.
    "mel-flag-stalled-smehub": {
        "task": "apps.mel.tracking.flag_stalled_smehub_records",
        "schedule": crontab(hour=6, minute=0),
    },
    # G16 — pre-due survey reminder (48 h before due_at).
    "mel-survey-pre-due-reminders": {
        "task": "mel.feedback.scan_due_survey_reminders",
        "schedule": crontab(minute=20, hour="*/2"),
    },
    # Phase 4.3 — post-due reminder + non-response escalation (pre-existing).
    "mel-survey-non-response-sweep": {
        "task": "mel.feedback.scan_survey_non_responses",
        "schedule": crontab(minute=40, hour="*/3"),
    },
    # G7 — daily scan for indicators whose responsible user hasn't reported.
    "mel-indicators-silent-scan": {
        "task": "mel.indicators.scan_silent_responsibles",
        "schedule": crontab(hour=8, minute=10),
    },
    # G6 — daily sweep for closed log frames whose post-project window has elapsed.
    "mel-post-project-tracers": {
        "task": "mel.feedback.scan_post_project_tracers",
        "schedule": crontab(hour=5, minute=15),
    },
    # G4 — nightly programme health recompute for active log frames.
    "mel-programme-health-recompute": {
        "task": "mel.indicators.recompute_programme_health",
        "schedule": crontab(hour=4, minute=30),
    },
    # M&E SRS Table 66 (E1/E4, Alert Generation) — these sweeps were implemented
    # but never scheduled: delayed activities, overdue outputs, nightly
    # compliance scan, and overdue corrective-action escalation.
    "mel-scan-delayed-activities": {
        "task": "apps.mel.tracking.scan_delayed_activities",
        "schedule": crontab(hour=5, minute=30),
    },
    "mel-scan-overdue-outputs": {
        "task": "apps.mel.tracking.scan_overdue_outputs",
        "schedule": crontab(hour=5, minute=45),
    },
    "mel-compliance-scan-nightly": {
        "task": "apps.mel.reports.run_compliance_scan_nightly",
        "schedule": crontab(hour=2, minute=30),
    },
    "mel-corrective-action-overdue": {
        "task": "apps.mel.tracking.scan_overdue_corrective_actions",
        "schedule": crontab(hour=6, minute=45),
    },
    # FRSME-INC021 — daily reminder to judges with outstanding scores.
    "smehub-incubation-remind-pending-judges": {
        "task": "smehub.incubation.remind_pending_judges",
        "schedule": crontab(hour=8, minute=0),
    },
    # FRSME-ISD016 — auto-close deal rooms past their expiry date.
    "smehub-showcasing-expire-deal-rooms": {
        "task": "smehub.showcasing.expire_deal_rooms",
        "schedule": crontab(hour=2, minute=30),
    },
    # FRSME-ISD016 — warn both parties of deal rooms expiring soon.
    "smehub-showcasing-warn-expiring-deal-rooms": {
        "task": "smehub.showcasing.warn_expiring_deal_rooms",
        "schedule": crontab(hour=7, minute=45),
    },
}
