"""Pull transactions, accounts, categories, and recurring expenses from Lunch Money into local SQLite.

Idempotent (upsert). Cron-safe.

Usage:
  python pull_transactions.py            # last 90 days
  python pull_transactions.py --days 30
"""
import argparse
import datetime as dt
import os
import sys
import time
from pathlib import Path

import requests

import db

ROOT = Path(__file__).parent
BASE_URL = "https://dev.lunchmoney.app/v1"


def _token():
    tok = os.environ.get("LUNCH_MONEY_TOKEN")
    if not tok:
        print("ERROR: LUNCH_MONEY_TOKEN not set. Add it to .env and source it.", file=sys.stderr)
        sys.exit(1)
    return tok


def _get(path, params=None):
    r = requests.get(
        f"{BASE_URL}{path}",
        headers={"Authorization": f"Bearer {_token()}"},
        params=params or {},
        timeout=30,
    )
    if r.status_code == 429:
        time.sleep(int(r.headers.get("Retry-After", "5")))
        return _get(path, params)
    r.raise_for_status()
    return r.json()


def pull_categories():
    data = _get("/categories")
    cats = data.get("categories", [])
    for c in cats:
        db.upsert_category(c)
    return len(cats)


def pull_accounts():
    n_assets = n_plaid = 0
    for a in _get("/assets").get("assets", []):
        db.upsert_asset(a)
        n_assets += 1
    for p in _get("/plaid_accounts").get("plaid_accounts", []):
        db.upsert_plaid_account(p)
        n_plaid += 1
    return n_assets, n_plaid


def pull_recurring():
    rows = _get("/recurring_expenses").get("recurring_expenses", [])
    for r in rows:
        db.upsert_recurring(r)
    return len(rows)


def pull_transactions(days: int):
    end = dt.date.today()
    start = end - dt.timedelta(days=days)
    total = 0
    offset = 0
    while True:
        data = _get("/transactions", {
            "start_date": start.isoformat(),
            "end_date": end.isoformat(),
            "limit": 500,
            "offset": offset,
        })
        txns = data.get("transactions", [])
        if not txns:
            break
        for t in txns:
            db.upsert_transaction(t)
        total += len(txns)
        if len(txns) < 500:
            break
        offset += len(txns)
    return total


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--days", type=int, default=90)
    args = ap.parse_args()

    db.init_db()
    print(f"Pulling last {args.days} days from Lunch Money…")
    n_cat = pull_categories()
    n_assets, n_plaid = pull_accounts()
    n_txn = pull_transactions(args.days)
    n_rec = pull_recurring()
    print(f"  categories: {n_cat}")
    print(f"  accounts: {n_assets} manual + {n_plaid} linked")
    print(f"  transactions: {n_txn}")
    print(f"  recurring expenses: {n_rec}")
    print("done.")


if __name__ == "__main__":
    main()
