#!/usr/bin/env python3
"""
Занос наличной выручки из AlfaCRM в Финтабло (счёт «Наличные»).

Использование:
    python enter_alfa_income.py <мм.гггг>            # dry-run: показать план
    python enter_alfa_income.py <мм.гггг> --commit    # реально занести
    пример: python enter_alfa_income.py 07.2026 --commit

Тянет наличные ПРИХОДЫ из AlfaCRM (кассы «Касса кэш» + «Личный счёт Саши», тип «Доход»)
за указанный месяц (по document_date) и заносит в Финтабло на счёт «Наличные»
как «Выручка b2c», по каждому платежу: дата = document_date, плательщик в описании.

Защита от задвоения: id платежа AlfaCRM пишется в externalId Финтабло; при повторе
такие платежи пропускаются. Плюс страховка по (дата+сумма) против ручных записей без externalId.
"""
import json, os, re, sys
from collections import defaultdict

import core

RR = 154399  # счёт «Наличные» в Финтабло
CASH_ACCOUNT_NAMES = ('касса кэш', 'личный счет саши')  # наличные кассы AlfaCRM


def main():
    args = [a for a in sys.argv[1:] if not a.startswith('--')]
    commit = '--commit' in sys.argv
    if not args or not re.match(r'\d{2}\.\d{4}$', args[0]):
        print("укажи месяц: python enter_alfa_income.py <мм.гггг> [--commit]"); return
    target = args[0]  # мм.гггг

    tok = core.alfa_login()

    # наличные кассы (id по имени). /pay-account/index отдаёт счета всех филиалов сразу.
    accnames = {a['id']: a['name']
                for a in core.alfa('/v2api/3/pay-account/index', {'page': 0}, tok).get('items', [])}
    cash_ids = [i for i, n in accnames.items() if any(c in n.lower() for c in CASH_ACCOUNT_NAMES)]
    if not cash_ids:
        print("⚠️ не нашла наличных касс в AlfaCRM — проверь названия"); return

    # ⚠️ даты ТОЛЬКО через дефисы: формат '2026.07.01' AlfaCRM молча игнорирует и отдаёт
    # всю историю (раньше так и было — скрипт качал тысячи записей и фильтровал их сам).
    date_from, date_to = core.month_range_alfa(target)
    pays = {}
    for br in core.BRANCHES:
        for acc in cash_ids:
            for x in core.alfa_all(f'/v2api/{br}/pay/index',
                                   {'pay_type_id': 1, 'pay_account_id': acc,
                                    'date_from': date_from, 'date_to': date_to}, tok):
                dd = (x.get('document_date') or '')
                if dd[3:] != target:           # страховка: границы периода ≠ document_date
                    continue
                pays[x['id']] = {'id': x['id'], 'date': dd,
                                 'income': round(float(x.get('income') or 0), 2),
                                 'payer': (x.get('payer_name') or '').strip(),
                                 'acc': accnames.get(acc, '')}
    plist = sorted(pays.values(), key=lambda p: (p['date'][6:], p['date'][3:5], p['date'][:2]))
    total = sum(p['income'] for p in plist)
    print(f"AlfaCRM наличных приходов за {target}: {len(plist)} на {total:,.0f} ₽")

    # --- Финтабло: статья, существующие (дедуп) ---
    cats = {x['name']: x['id'] for x in core.ftget('/v1/category')['items']}
    vb2c = cats.get('Выручка b2c')
    if not vb2c:
        print("⚠️ в Финтабло нет статьи «Выручка b2c»"); return
    tx = core.ft_transactions(year=int(target[3:]), moneybagId=RR)
    inc = [t for t in tx if t.get('group') == 'income' and not t.get('isPlan')]
    seen_ext = {t.get('externalId') for t in inc if t.get('externalId')}
    seen_da = defaultdict(int)
    for t in inc:
        seen_da[(t['date'], round(t['value'], 2))] += 1

    to_add, skip_ext, skip_da = [], 0, []
    for p in plist:
        ext = f"alfa:{p['id']}"
        if ext in seen_ext:
            skip_ext += 1; continue
        if seen_da.get((p['date'], p['income']), 0) > 0:  # страховка от ручных дублей
            seen_da[(p['date'], p['income'])] -= 1; skip_da.append(p); continue
        to_add.append(p)

    addsum = sum(p['income'] for p in to_add)
    print(f"к заносу: {len(to_add)} на {addsum:,.0f} | пропущено по externalId (точный дубль): {skip_ext}")
    # Пропуски по (дата, сумма) — страховка от ручных дублей, но может съесть легитимный
    # второй платёж в тот же день на ту же сумму. Печатаем построчно для проверки глазами.
    if skip_da:
        print(f"⚠ пропущено как возможный дубль по (дата, сумма): {len(skip_da)} — проверь, нет ли легитимных:")
        for p in sorted(skip_da, key=lambda x: x['date']):
            print(f"   ⏭ {p['date']} | {p['income']:>9,.0f} | {p['payer'] or 'Наличная выручка (AlfaCRM)'}")
    bal = core.ft_moneybag_balance(RR)
    print(f"остаток «Наличные» сейчас {bal:,.0f} → после ≈ {bal + addsum:,.0f}")

    if not commit:
        print("\n(dry-run — ничего не записано. --commit чтобы занести.)"); return

    log = []
    for p in to_add:
        body = {'value': p['income'], 'group': 'income', 'moneybagId': RR, 'date': p['date'],
                'categoryId': vb2c, 'factMonth': target, 'externalId': f"alfa:{p['id']}",
                'description': p['payer'] or 'Наличная выручка (AlfaCRM)'}
        res = core.ftmut('POST', '/v1/transaction', body)
        tid = res.get('id') if isinstance(res, dict) else None
        if tid:
            log.append({'id': tid, 'alfa_id': p['id'], 'date': p['date'],
                        'value': p['income'], 'payer': p['payer']})
        else:
            print("  ✗", p, res)
    out = os.path.join(core.HERE, 'exports', f'alfa_income_{target}.json')
    os.makedirs(os.path.dirname(out), exist_ok=True)
    with open(out, 'w', encoding='utf-8') as fh:
        json.dump(log, fh, ensure_ascii=False, indent=1)
    print(f"занесено: {len(log)} на {sum(x['value'] for x in log):,.0f} | "
          f"остаток «Наличные»: {core.ft_moneybag_balance(RR):,.0f}")
    print(f"лог (откат): {out}")


if __name__ == '__main__':
    main()
