# src/jobs/subscription_renewal.py
# root 사용자 crontab (sudo crontab -e)
# 
# CRON_TZ=Asia/Seoul
# 10 0 * * * /bin/bash -lc 'cd /var/www/html/BatchJob && /usr/bin/python3 -c "from src.jobs.subscription_renewal import run_subscription_renewals_batch as r; import json; print(json.dumps(r()))" >> /var/log/subscription_renewal.log 2>&1'
# 
from datetime import datetime, date
from zoneinfo import ZoneInfo
from sqlalchemy import and_
from src.models.db import db
from src.models.subscription import Subscription, SubscriptionStatus, Product
from src.utils.credit_manager import add_credits, CreditType

KST = ZoneInfo("Asia/Seoul")

def _monthly_credit_for_product(product_name: str):
    name = (product_name or "").lower()
    if "Pro" in name:
        return 19000, CreditType.SUBSCRIPTION_PRO
    if "Plus" in name:
        return 3900, CreditType.SUBSCRIPTION_PLUS
    return 1900, CreditType.SUBSCRIPTION_BASIC

def _add_one_month_same_day(base_date: date, start_day: int) -> date:
    """base_date 기준으로 +1개월, 시작일의 '일(day)' 유지. 말일 보정."""
    # 다음 달 임시 날짜
    if base_date.month == 12:
        y, m = base_date.year + 1, 1
    else:
        y, m = base_date.year, base_date.month + 1

    # 다음 달 말일
    from calendar import monthrange
    last_day = monthrange(y, m)[1]
    keep_day = min(start_day, last_day)
    return date(y, m, keep_day)

def run_subscription_renewals_batch():
    """KST 오늘 지급 대상 구독을 모두 처리 (연간 선결제 포함)"""
    now_kst = datetime.now(KST)
    today = now_kst.date()

    # 대상: 활성 + next_credit_date가 오늘 또는 NULL
    subs: list[Subscription] = Subscription.query.filter(
        Subscription.status == SubscriptionStatus.ACTIVE,
        (Subscription.next_credit_date == None) | (Subscription.next_credit_date <= today)
    ).all()

    results = {"processed": 0, "granted": 0, "errors": []}

    for s in subs:
        try:
            # product 조회
            product = Product.query.get(s.product_id) if s.product_id else None
            credit_amount, credit_type = _monthly_credit_for_product(product.name if product else None)

            # 지급
            res = add_credits(
                user_id=s.user_id,
                credit_type=credit_type,
                amount=credit_amount,
                description=f"{product.name if product else '구독'} 월간 크레딧 자동 지급",
                reference_id=str(s.id),
                reference_type="subscription_credit"
            )
            if not res.get("success"):
                raise RuntimeError(res.get("error") or "add_credits 실패")

            # 다음 지급일 계산 (시작일의 같은 날짜, 말일 보정)
            start_local = s.started_at.astimezone(KST) if isinstance(s.started_at, datetime) else datetime.now(KST)
            start_day = start_local.day
            base = s.next_credit_date or start_local.date()
            next_credit_date = _add_one_month_same_day(base, start_day)

            # 선결제: 연간 & 잔여 선결제 > 0 → 차감
            if s.billing_cycle == "ANNUAL" and (s.prepaid_cycles_remaining or 0) > 0:
                s.prepaid_cycles_remaining = (s.prepaid_cycles_remaining or 0) - 1

            s.last_credit_date = today
            s.next_credit_date = next_credit_date

            db.session.commit()
            results["processed"] += 1
            results["granted"] += credit_amount
        except Exception as e:
            db.session.rollback()
            results["errors"].append({"subscription_id": s.id, "error": str(e)})

    return results
