#!/usr/bin/env python3
"""
ATIME CDR Reporting Tool — CLI entry point.

One-time:
    python3 report.py --seed ATIME_CDR_2025_full.csv.gz   # load an export into SQLite

Ad-hoc reports (default: all regions; add --region cleveland|florida|nyc for one):
    python3 report.py --year 2025
    python3 report.py --ytd
    python3 report.py --start 2025-01-01 --end 2025-03-31
    python3 report.py --pull --ytd                        # refresh from API first

Monthly production run (cron on ns-scripts, fires the 1st of each month):
incremental pull -> 18-month prune -> then, per region, render + email
  1. the previous month's report (e.g. "June 2026"), and
  2. the year-to-date report (Jan 1 -> end of previous month);
     on Jan 1 this window is the full prior year, so it is sent once,
     labeled as the "<year> Annual" report.

    python3 report.py --monthly
    Cron:  0 6 1 * *  cd /opt/ns-scripts/atime-reports && ./venv/bin/python report.py --monthly
"""

import argparse
import json
import os
from datetime import datetime, timezone, timedelta, date

import config
import analyze
import render_html
import render_xlsx
import email_send


def _eastern_now():
    return datetime.now(timezone(timedelta(hours=-5)))


def _prev_month_end(today):
    """Last day of the month before `today` (a date)."""
    first_of_this = today.replace(day=1)
    return first_of_this - timedelta(days=1)


def _resolve_window(args):
    """Return (start, end, label, period_label) where start/end are 'YYYY-MM-DD' or None."""
    now = _eastern_now().date()
    if args.start or args.end:
        start, end = args.start, args.end
        lab = f'{start or "begin"}_{end or "now"}'
        return start, end, lab, f'{start or "start"} to {end or "latest"}'
    if args.year:
        return f"{args.year}-01-01", f"{args.year}-12-31", str(args.year), str(args.year)
    if args.ytd or args.weekly:
        return f"{now.year}-01-01", now.strftime("%Y-%m-%d"), f"{now.year}_YTD", f"{now.year} year-to-date"
    return None, None, "all", "all available data"


def _monthly_windows(now):
    """The two report windows for the cron run on the 1st of the month.

    1. The previous full month ("June 2026").
    2. Year-to-date through the end of that month; when the previous month is
       December this is the whole prior year, sent once as the Annual report.
    """
    pme = _prev_month_end(now)
    first = pme.replace(day=1)
    windows = [(first.strftime("%Y-%m-%d"), pme.strftime("%Y-%m-%d"),
                f"{pme:%Y-%m}_Monthly", f"{pme:%B %Y}")]
    if pme.month == 12:
        windows.append((f"{pme.year}-01-01", pme.strftime("%Y-%m-%d"),
                        f"{pme.year}_Annual", f"{pme.year} Annual"))
    else:
        windows.append((f"{pme.year}-01-01", pme.strftime("%Y-%m-%d"),
                        f"{pme.year}_YTD_{pme:%b}", f"{pme.year} YTD through {pme:%B}"))
    return windows


def _email_body(metrics, region_key, period_label):
    """Short, robust HTML summary for the email body (full report is attached)."""
    C = config.BRAND
    s = metrics["summary"]
    f = lambda n: f"{int(round(float(n))):,}"
    reg = metrics["regions"].get(region_key) if region_key else None
    accent = reg["meta"]["accent"] if reg else C["orange"]
    chip = f"A&nbsp;TIME &middot; Call Activity{(' &middot; ' + reg['meta']['display']) if reg else ''}"
    intro = (f"Prepared for our {reg['meta']['display']} supporters by PressONE."
             if reg else "Prepared for A&nbsp;TIME by PressONE.")
    region_rows = ""
    if reg:
        rm, cs = reg["meta"], reg["summary"]
        region_rows = f"""
<tr><td style="padding:4px 16px 4px 0;color:{C['muted']}">{rm['display']} inbound calls</td>
<td style="font-weight:700;color:{rm['accent']}">{f(cs['inbound_attempts'])}</td></tr>
<tr><td style="padding:4px 16px 4px 0;color:{C['muted']}">{rm['display']} families (unique callers)</td>
<td style="font-weight:700;color:{rm['accent']}">{f(cs['unique_callers'])}</td></tr>
<tr><td style="padding:4px 16px 4px 0;color:{C['muted']}">{rm['display']} talk time (hrs)</td>
<td style="font-weight:700;color:{rm['accent']}">{f(cs['talk_hours'])}</td></tr>"""
    else:
        region_rows = f"""
<tr><td style="padding:4px 16px 4px 0;color:{C['muted']}">Total inbound attempts</td>
<td style="font-weight:700;color:{C['purple_deep']}">{f(s['inbound_attempts'])}</td></tr>
<tr><td style="padding:4px 16px 4px 0;color:{C['muted']}">Unique callers</td>
<td style="font-weight:700;color:{C['purple_deep']}">{f(s['unique_callers'])}</td></tr>
<tr><td style="padding:4px 16px 4px 0;color:{C['muted']}">Answer rate</td>
<td style="font-weight:700;color:{C['purple_deep']}">{s['answer_rate']}%</td></tr>"""
    return f"""<div style="font-family:'Inter',Arial,sans-serif;color:{C['text']};max-width:560px">
<div style="color:{accent};font-weight:700;font-size:12px;letter-spacing:.12em;text-transform:uppercase">
{chip}</div>
<h2 style="color:{C['purple_deep']};margin:6px 0 2px">{period_label}</h2>
<p style="color:{C['muted']};font-size:14px;margin:0 0 16px">{intro}</p>
<table style="border-collapse:collapse;font-size:14px">
<tr><td style="padding:4px 16px 4px 0;color:{C['muted']}">Calls answered live (all divisions)</td>
<td style="font-weight:700;color:{C['purple_deep']}">{f(s['inbound_answered'])}</td></tr>
<tr><td style="padding:4px 16px 4px 0;color:{C['muted']}">Hours with inbound callers</td>
<td style="font-weight:700;color:{C['purple_deep']}">{f(s['talk_hours_inbound'])}</td></tr>
<tr><td style="padding:4px 16px 4px 0;color:{C['muted']}">Outbound follow-up calls (hrs)</td>
<td style="font-weight:700;color:{C['purple_deep']}">{f(s['outbound'])} ({f(s['talk_hours_outbound'])})</td></tr>{region_rows}
</table>
<p style="font-size:13px;color:{C['muted']};margin-top:18px">The full branded report (HTML) and the data workbook (Excel)
are attached. Open the HTML file in any browser to view or print.</p>
</div>"""


def generate(metrics, label, region_key, want_html=True, want_xlsx=True):
    """Render artifacts for one region (region_key=None => generic). Return (html, xlsx)."""
    suffix = "_" + config.REGIONS[region_key]["name"].replace(" ", "") if region_key else ""
    html_path = xlsx_path = None
    if want_html:
        html_path = os.path.join(config.OUTPUT_DIR, f"ATIME_{label}{suffix}_Report.html")
        with open(html_path, "w") as fh:
            fh.write(render_html.render(metrics, region_key))
    if want_xlsx:
        xlsx_path = os.path.join(config.OUTPUT_DIR, f"ATIME_{label}{suffix}_Call_Data.xlsx")
        render_xlsx.render(metrics, xlsx_path, region_key)
    return html_path, xlsx_path


def email_region(metrics, region_key, label, period_label, html_path, xlsx_path):
    if region_key:
        to = config.EMAIL["recipients"].get(region_key, [])
        subject = f"A TIME — {config.REGIONS[region_key]['display']} Call Activity ({period_label})"
    else:
        to = config.EMAIL["recipients"].get("generic", [])
        subject = f"A TIME — Call Activity ({period_label})"
    attachments = []
    if html_path:
        with open(html_path, "rb") as f:
            attachments.append((os.path.basename(html_path), f.read(), "text/html"))
    if xlsx_path:
        with open(xlsx_path, "rb") as f:
            attachments.append((os.path.basename(xlsx_path), f.read(),
                                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"))
    body = _email_body(metrics, region_key, period_label)
    return email_send.send_email(to, subject, body, attachments)


def main():
    ap = argparse.ArgumentParser(description="ATIME CDR reporting tool")
    ap.add_argument("--seed", metavar="CSV", help="seed SQLite from a CSV/.csv.gz export, then exit")
    ap.add_argument("--pull", action="store_true", help="incremental API pull before reporting")
    ap.add_argument("--monthly", action="store_true",
                    help="cron mode: pull + 18-mo prune + YTD report per region + email each")
    ap.add_argument("--weekly", action="store_true", help="incremental pull + YTD report")
    ap.add_argument("--ytd", action="store_true", help="report Jan 1 -> today")
    ap.add_argument("--year", type=int, help="report a full calendar year")
    ap.add_argument("--start", help="range start YYYY-MM-DD")
    ap.add_argument("--end", help="range end YYYY-MM-DD")
    ap.add_argument("--region", choices=list(config.REGIONS), help="limit to one region")
    ap.add_argument("--generic", action="store_true",
                    help="produce the generic org-wide report (no regional section)")
    ap.add_argument("--email", action="store_true", help="email reports (implied by --monthly)")
    ap.add_argument("--no-html", action="store_true")
    ap.add_argument("--no-xlsx", action="store_true")
    args = ap.parse_args()

    os.makedirs(config.OUTPUT_DIR, exist_ok=True)

    if args.seed:
        import pull
        pull.seed_from_csv(args.seed)
        return

    if args.pull or args.monthly or args.weekly:
        import pull
        try:
            pull.pull_departments()
        except Exception as e:  # noqa: BLE001
            print(f"[!] department pull failed ({e}); using cached departments.")
        try:
            pull.incremental()
        except Exception as e:  # noqa: BLE001
            print(f"[!] incremental pull failed ({e}); reporting on existing DB.")
        if args.monthly:
            pull.prune_older_than(config.RETENTION_MONTHS)

    # target selection: --region X -> [X]; --generic -> [None]; default -> all regions
    if args.region:
        regions = [args.region]
    elif args.generic:
        regions = [None]
    else:
        regions = list(config.REGIONS)
    do_email = args.email or args.monthly

    # --monthly runs two windows (previous month + YTD/Annual); everything else one.
    if args.monthly:
        windows = _monthly_windows(_eastern_now().date())
    else:
        windows = [_resolve_window(args)]

    for start, end, label, period_label in windows:
        generated_at = _eastern_now().strftime("%Y-%m-%d %H:%M %Z")
        print(f"Analyzing {label}  ({start or 'begin'} .. {end or 'latest'}) ...")
        metrics, _df = analyze.run(start=start, end=end, generated_at=generated_at)
        metrics["meta"]["period_label"] = period_label

        json_path = os.path.join(config.OUTPUT_DIR, f"metrics_{label}.json")
        with open(json_path, "w") as f:
            json.dump(metrics, f, indent=2)
        print(f"  wrote {json_path}")

        for rk in regions:
            html_path, xlsx_path = generate(metrics, label, rk,
                                            want_html=not args.no_html, want_xlsx=not args.no_xlsx)
            print(f"  [{rk or 'generic'}] {os.path.basename(html_path or '')}  {os.path.basename(xlsx_path or '')}")
            if do_email:
                email_region(metrics, rk, label, period_label, html_path, xlsx_path)

        analyze._print_validation(metrics)


if __name__ == "__main__":
    main()
