#!/usr/bin/env python3
"""
Поиск документов в SQLite для чат-бота.
Вызывается из bot.php через shell_exec при tool call от AI.

Использование:
    python3 search_db.py --query '{"contractor": "РКГ", "limit": 10}'
"""

import argparse
import json
import os
import re
import sqlite3

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DB_PATH  = os.path.join(BASE_DIR, 'baseDoc', 'data', 'documents.db')

# Все невидимые/форматирующие unicode-символы, которые AI вставляет в аргументы
_INVISIBLE = re.compile(
    r'[\u00ad\u200b-\u200f\u2028-\u202f\u2060-\u206f\ufeff'
    r'\u00a0\u1680\u2000-\u200a\u205f\u3000]'
)

def clean(s: str) -> str:
    """Заменяет невидимые символы на пробел (чтобы не склеивать слова) и нормализует пробелы."""
    s = _INVISIBLE.sub(' ', s)
    s = re.sub(r' {2,}', ' ', s)
    return s.strip()

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


def search(params: dict) -> str:
    if not os.path.exists(DB_PATH):
        return f'База данных не найдена: {DB_PATH}'

    conn = sqlite3.connect(DB_PATH)
    # Кастомная функция — case-insensitive для кириллицы
    conn.create_function('lower_ru', 1, lambda x: x.lower() if x else '')

    conditions = []
    args = []

    contractor_raw = params.get('contractor', '')
    if isinstance(contractor_raw, str):
        contractor = clean(contractor_raw)
    else:
        contractor = str(contractor_raw).strip()
    if contractor:
        # Извлекаем только буквенно-цифровые слова (кириллица + латиница + цифры)
        # Это защищает от любых невидимых символов между словами
        LEGAL = {'ООО', 'ЗАО', 'ОАО', 'ПАО', 'АО', 'ИП', 'НКО', 'ГУП', 'МУП', 'ФГУП'}
        all_words = re.findall(r'[а-яёА-ЯЁa-zA-Z0-9]{2,}', contractor)
        search_words = [w for w in all_words if w.upper() not in LEGAL]
        if not search_words:
            search_words = all_words if all_words else [contractor]
        for w in search_words:
            conditions.append('lower_ru(contractor) LIKE lower_ru(?)')
            args.append(f'%{w}%')

    contract_ref = clean(params.get('contract_ref', ''))
    if contract_ref:
        conditions.append(
            '(lower_ru(contract_refs) LIKE lower_ru(?) '
            'OR lower_ru(num_date_str) LIKE lower_ru(?) '
            'OR lower_ru(name) LIKE lower_ru(?))'
        )
        args += [f'%{contract_ref}%', f'%{contract_ref}%', f'%{contract_ref}%']

    # date_create хранится как DD.MM.YYYY → переводим в YYYYMMDD для сравнения
    # substr(date_create,7,4)||substr(date_create,4,2)||substr(date_create,1,2) → '20260101'
    date_from = clean(params.get('date_from', ''))
    if date_from:
        iso = date_from.replace('-', '')  # '2026-01-01' → '20260101'
        conditions.append(
            "(substr(date_create,7,4)||substr(date_create,4,2)||substr(date_create,1,2)) >= ?"
        )
        args.append(iso)

    date_to = clean(params.get('date_to', ''))
    if date_to:
        iso = date_to.replace('-', '')
        conditions.append(
            "(substr(date_create,7,4)||substr(date_create,4,2)||substr(date_create,1,2)) <= ?"
        )
        args.append(iso)

    status = clean(params.get('status', ''))
    if status:
        conditions.append('lower_ru(status) LIKE lower_ru(?)')
        args.append(f'%{status}%')

    payer = clean(params.get('payer', ''))
    if payer:
        conditions.append('lower_ru(payer) LIKE lower_ru(?)')
        args.append(f'%{payer}%')

    limit = min(int(params.get('limit', 10)), 20)

    if not conditions:
        conn.close()
        return 'Укажите хотя бы один параметр поиска: контрагент, номер договора, дату или статус.'

    where = 'WHERE ' + ' AND '.join(conditions)

    # Сначала получаем общее количество
    count = conn.execute(
        f'SELECT COUNT(*) FROM documents {where}', args
    ).fetchone()[0]

    rows = conn.execute(f'''
        SELECT element_id, name, contractor, date_create, amount, status,
               doc_types, contract_refs, has_analysis
        FROM documents
        {where}
        ORDER BY date_create DESC
        LIMIT ?
    ''', args + [limit]).fetchall()

    conn.close()

    if not rows:
        return 'Документы по заданным критериям не найдены.'

    lines = [f'Найдено: {count} документов (показано {len(rows)})\n']
    for r in rows:
        doc_types = json.loads(r[6] or '[]')
        refs      = json.loads(r[7] or '[]')
        name      = (r[1] or '—')[:80]
        lines.append(f'ID={r[0]} | {r[3]} | {r[4] or "—"} руб. | {r[5]}')
        lines.append(f'  {name}')
        if r[2]:      lines.append(f'  Контрагент: {r[2]}')
        if doc_types: lines.append(f'  Типы: {", ".join(doc_types)}')
        if refs:      lines.append(f'  Договоры: {", ".join(refs)}')
        if r[8]:      lines.append(f'  [есть AI-анализ]')
        lines.append('')

    return '\n'.join(lines)


def main():
    import sys
    ap = argparse.ArgumentParser()
    ap.add_argument('--query', required=True, help='JSON-параметры поиска')
    args = ap.parse_args()

    # DEBUG: что получил скрипт
    raw = args.query
    sys.stderr.write(f'[DBG] raw_query bytes={len(raw.encode())}\n')
    sys.stderr.write(f'[DBG] raw_query repr={repr(raw[:200])}\n')

    try:
        params = json.loads(raw)
    except json.JSONDecodeError as e:
        print(f'Ошибка парсинга JSON: {e}')
        sys.stderr.write(f'[DBG] JSON parse error: {e}\n')
        return

    # DEBUG: что извлекли из JSON
    contractor_raw = params.get('contractor', '')
    sys.stderr.write(f'[DBG] contractor repr={repr(contractor_raw)}\n')
    sys.stderr.write(f'[DBG] contractor bytes={contractor_raw.encode("utf-8").hex()}\n')

    print(search(params))


if __name__ == '__main__':
    main()
