#!/usr/bin/env python3
"""
Ищет связанные документы по element_id:
  1. По контрагенту (свежие)
  2. По договору/ДС если есть ссылки в документе

Использование:
    python3 search_similar.py --id 66999 --top 10
"""

import argparse
import json
import os
import re
import sqlite3

import requests

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DB_PATH  = os.path.join(BASE_DIR, 'baseDoc', 'data', 'documents.db')
WEBHOOK  = 'https://engeocentr.bitrix24.ru/rest/4391/n8rq6nyzr9z8tvdz/'

SELECT = [
    'ID', 'NAME', 'DATE_CREATE', 'PROPERTY_1367', 'PROPERTY_423',
    'PROPERTY_389', 'PROPERTY_391', 'PROPERTY_383',
    'PROPERTY_421', 'PROPERTY_401', 'PROPERTY_427',
    'PROPERTY_387', 'PROPERTY_413',
    'PROPERTY_415', 'PROPERTY_451', 'PROPERTY_503', 'PROPERTY_2185',
    'PROPERTY_2989',
]

PAYER_MAP  = {'373': 'БДК', '375': 'ТЗК', '377': 'ИНГЕО', '1059': 'ВЦПО'}
STATUS_MAP = {'363': 'Отклонено', '365': 'Согласовано',
              '367': 'Согласовано и распечатано', '419': 'Не установлен'}
OBJECT_MAP = {
    '1071': 'Камергер (общий)', '1073': 'Дмитровка (общий)',
    '15881': 'БД-ПА', '15883': 'КА-НС', '15885': 'КА-ПА',
    '17363': 'Стр.7 Б. Дмитровка, дом.9', '39129': 'БД-НС',
}
DOC_PATTERNS = [
    ('КС-2/КС-3', r'КС-2\s*/\s*КС-3'), ('УПД', r'\bУПД\b'),
    ('Счет-фактура', r'[Сс]чет-фактура|[Сс]ч-ф\b'), ('Акт', r'\bАкт\b'),
    ('Счет', r'[Сс]чет\s*№'), ('КС-2', r'КС-2\b'), ('КС-3', r'КС-3\b'),
    ('Справка', r'[Сс]правка'), ('Договор', r'Дог(?:овор)?\.?\s*№'), ('ДС', r'\bДС\s*№'),
]


def scalar(field):
    if not field: return ''
    if isinstance(field, dict):
        vals = list(field.values())
        return vals[0] if vals else ''
    return field

def multi_values(field):
    if not field: return []
    if isinstance(field, dict):
        vals = list(field.values())
        if vals and isinstance(vals[0], list): return vals[0]
        return [str(v) for v in vals if v]
    if isinstance(field, list): return field
    return [str(field)]

def parse_doc_types(text):
    found = []
    for name, pat in DOC_PATTERNS:
        if re.search(pat, text or ''): found.append(name)
    return list(dict.fromkeys(found))

def extract_contract_refs(text):
    refs = []
    for m in re.findall(r'к\s*Договору\s*№\s*([\w\d\.\-\/]+)', text or ''):
        refs.append(m)
    for m in re.findall(r'по\s*ДС\s*№\s*([\w\d\.]+)', text or ''):
        refs.append(m)
    return refs

def strip_html(text):
    if not text: return ''
    return re.sub(r'<[^>]+>', ' ', text).strip()

def get_analysis_text(item):
    res = scalar(item.get('PROPERTY_2989'))
    if isinstance(res, dict): return res.get('TEXT', '')
    return res or ''

def fetch_element(element_id):
    resp = requests.post(WEBHOOK + 'lists.element.get', json={
        'IBLOCK_TYPE_ID': 'bitrix_processes', 'IBLOCK_ID': '57',
        'FILTER': {'ID': element_id}, 'SELECT': SELECT,
    }, timeout=30)
    resp.raise_for_status()
    items = resp.json().get('result', [])
    if not items:
        raise ValueError(f'Элемент {element_id} не найден')
    return items[0]

def build_record(item):
    nom_dat   = scalar(item.get('PROPERTY_391', ''))
    title     = item.get('NAME', '')
    file_ids  = []
    for prop in ['PROPERTY_415', 'PROPERTY_451', 'PROPERTY_503', 'PROPERTY_2185']:
        file_ids += multi_values(item.get(prop))
    payer_id  = str(scalar(item.get('PROPERTY_427', '')))
    status_id = str(scalar(item.get('PROPERTY_401', '')))
    obj_id    = str(scalar(item.get('PROPERTY_387', '')))
    analysis  = get_analysis_text(item)
    return {
        'element_id':    item['ID'],
        'name':          title,
        'date_create':   item.get('DATE_CREATE', '')[:10],
        'contractor':    scalar(item.get('PROPERTY_1367', '')),
        'payer':         PAYER_MAP.get(payer_id, payer_id),
        'doc_types':     parse_doc_types(nom_dat) or parse_doc_types(title),
        'num_date_str':  nom_dat,
        'contract_refs': extract_contract_refs(nom_dat),
        'amount':        scalar(item.get('PROPERTY_421', '')),
        'status':        STATUS_MAP.get(status_id, status_id),
        'object':        OBJECT_MAP.get(obj_id, scalar(item.get('PROPERTY_387', ''))),
        'comment':       scalar(item.get('PROPERTY_413', '')),
        'file_ids':      [f for f in file_ids if f],
        'has_analysis':  bool(analysis),
        'analysis_text': analysis,
    }

def print_row(label, rows, exclude_id=None):
    if not rows:
        print(f'  (нет)')
        return
    for r in rows:
        if r[0] == exclude_id:
            continue
        # r: element_id, name, contractor, payer, amount, doc_types, contract_refs,
        #    status, has_analysis, analysis_text, date_create
        doc_types = json.loads(r[5] or '[]')
        refs      = json.loads(r[6] or '[]')
        print(f'  ID={r[0]} | {r[10]} | {r[1] or "—"}')
        print(f'    Контрагент: {r[2] or "—"} | Сумма: {r[4] or "—"} | Статус: {r[7]}')
        if doc_types:
            print(f'    Типы: {doc_types}')
        if refs:
            print(f'    Договоры: {refs}')
        if r[8]:  # has_analysis
            print(f'    Анализ: {strip_html(r[9])[:150]}...' if len(r[9] or '') > 150 else f'    Анализ: {strip_html(r[9] or "")}')
        print()


COLS = ('element_id, name, contractor, payer, amount, doc_types, contract_refs, '
        'status, has_analysis, analysis_text, date_create')


def search_by_contractor(conn, contractor, exclude_id, top):
    rows = conn.execute(
        f'SELECT {COLS} FROM documents '
        'WHERE contractor = ? AND element_id != ? '
        'ORDER BY date_create DESC LIMIT ?',
        (contractor, exclude_id, top)
    ).fetchall()
    print_row('contractor', rows, exclude_id)


def search_by_refs(conn, refs, exclude_id, top):
    matched = []
    for ref in refs:
        like_ref = f'%{ref}%'
        rows = conn.execute(
            f'SELECT {COLS} FROM documents '
            'WHERE (contract_refs LIKE ? OR num_date_str LIKE ? OR name LIKE ?) '
            'AND element_id != ? '
            'ORDER BY date_create DESC LIMIT ?',
            (like_ref, like_ref, like_ref, exclude_id, top)
        ).fetchall()
        matched += rows
    seen = set()
    unique = []
    for r in sorted(matched, key=lambda x: x[9], reverse=True):
        if r[0] not in seen:
            seen.add(r[0])
            unique.append(r)
    print_row('refs', unique[:top], exclude_id)


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument('--id',   default='', help='element_id элемента в Битрикс24')
    ap.add_argument('--refs', default='', help='Реквизиты договора через запятую (из AI-анализа)')
    ap.add_argument('--top',  type=int, default=10)
    args = ap.parse_args()

    element_id = str(args.id).strip()
    ai_refs    = [r.strip() for r in args.refs.split(',') if r.strip()]
    top        = args.top

    conn = sqlite3.connect(DB_PATH)

    # ── Режим 1: поиск по element_id (до AI-анализа) ─────────────────────────
    if element_id:
        item   = fetch_element(element_id)
        record = build_record(item)

        print(f'=== ТЕКУЩИЙ ДОКУМЕНТ [{element_id}] ===')
        print(f'  Название:    {record["name"][:100]}')
        print(f'  Контрагент:  {record["contractor"] or "—"}')
        print(f'  Плательщик:  {record["payer"]}')
        print(f'  Объект:      {record["object"] or "—"}')
        print(f'  Типы:        {record["doc_types"]}')
        print(f'  Сумма:       {record["amount"] or "—"}')
        print(f'  Статус:      {record["status"]}')
        print(f'  Реф. договоры: {record["contract_refs"]}')
        print(f'  Файлы:       {record["file_ids"]}')
        print()

        contractor = record['contractor']
        if contractor:
            print(f'=== ДОКУМЕНТЫ КОНТРАГЕНТА "{contractor}" (последние {top}) ===')
            search_by_contractor(conn, contractor, element_id, top)
        else:
            print('=== КОНТРАГЕНТ НЕ ЗАПОЛНЕН — поиск по контрагенту пропущен ===\n')

        meta_refs = record['contract_refs']
        if meta_refs:
            print(f'=== ДОКУМЕНТЫ В РАМКАХ ДОГОВОРА {meta_refs} ===')
            search_by_refs(conn, meta_refs, element_id, top)
        else:
            print('=== НЕТ ССЫЛОК НА ДОГОВОР В МЕТАДАННЫХ ===\n')

    # ── Режим 2: поиск по реквизитам из AI-анализа (после AI) ───────────────
    if ai_refs:
        exclude = element_id if element_id else '0'
        print(f'=== ДОКУМЕНТЫ ПО РЕКВИЗИТАМ ИЗ AI-АНАЛИЗА: {ai_refs} ===')
        search_by_refs(conn, ai_refs, exclude, top)

    conn.close()


if __name__ == '__main__':
    main()
