"""
Сборка результата обфускации.

Два метода:
1. _build_zip — упаковка обфусцированных файлов в ZIP
2. _build_mapping_csv — генерация mapping.csv с таблицей замен
"""

import io
import csv
import zipfile
import re
import time
from typing import Dict, List, Tuple

from .config import ENTITY_PATTERNS, COMPANY_PATTERN


def build_zip(files: List[Tuple[str, bytes]], mapping_csv: str = "") -> bytes:
    """Собрать ZIP-архив с обфусцированными файлами.

    В архив добавляются:
    - Все обфусцированные файлы (с оригинальными именами)
    - mapping.csv — таблица соответствия оригинал→замена (если не пустая)

    Имена файлов в архиве — UTF-8 (бит 11 в flag_bits).

    Args:
        files: [(filename, content_bytes), ...]
        mapping_csv: Строка CSV с таблицей замен (опционально)

    Returns:
        Бинарное содержимое ZIP-архива
    """
    buf = io.BytesIO()

    with zipfile.ZipFile(buf, 'w', zipfile.ZIP_DEFLATED) as zf:
        # Добавляем обфусцированные файлы
        for fname, content in files:
            info = zipfile.ZipInfo(fname)
            info.date_time = time.localtime(time.time() + 3 * 3600)[:6]  # MSK (UTC+3)
            info.flag_bits |= 0x800  # Флаг: имя файла в UTF-8
            zf.writestr(info, content)

        # Добавляем mapping.csv с BOM (для корректного открытия в Excel)
        if mapping_csv:
            zf.writestr(
                "mapping.csv",
                '\ufeff'.encode('utf-8') + mapping_csv.encode('utf-8'),
            )

    return buf.getvalue()


def build_mapping_csv(mapping: Dict[str, str]) -> str:
    """Собрать mapping.csv — таблицу соответствия оригинал → замена.

    Колонки:
    - тип_данных: тип сущности (phone, email, inn_ul, company, ...)
    - оригинал: исходное значение из документа
    - замена: фиктивное значение

    Тип определяется проверкой каждого значения через ENTITY_PATTERNS
    и COMPANY_PATTERN. Если ни один паттерн не подошёл — тип "text".

    Args:
        mapping: Словарь {оригинал: замена}

    Returns:
        Строка в формате CSV
    """
    buf = io.StringIO()
    writer = csv.writer(buf)
    writer.writerow(["тип_данных", "оригинал", "замена"])

    # Порядок проверки типов: inn_fl ДО inn_ul (12 цифр vs 10)
    type_order = [
        "phone", "email", "inn_fl", "inn_ul", "ogrn",
        "kpp", "bik", "rs", "ks", "passport",
    ]

    for original, replacement in sorted(mapping.items()):
        # Определяем тип сущности
        etype = "text"  # По умолчанию

        for t in type_order:
            pat = ENTITY_PATTERNS.get(t, "")
            if pat and re.match(pat, original, re.IGNORECASE):
                etype = t
                break

        # Компании проверяем отдельно (COMPANY_PATTERN не в ENTITY_PATTERNS)
        if COMPANY_PATTERN.match(original):
            etype = "company"

        writer.writerow([etype, original, replacement])

    return buf.getvalue()
