#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import re
from pathlib import Path
import pandas as pd

# ── НАСТРОЙКИ (поменяйте под себя) ────────────────────────────────────────────
BASE_DIR = Path("/Users/valis/Downloads/")  # папка, где лежат файлы
INPUT_XLSX_NAME = "Книга3.xlsx"        # имя исходного XLSX
SHEET_NAME = "orders"                        # имя листа или None (первый лист)
OUTPUT_VCF_NAME = "contacts.vcf"         # общее vcf с ВСЕМИ контактами
# ───────────────────────────────────────────────────────────────────────────────

# распознаваемые заголовки столбцов
FIRST_NAMES = {"first_name", "firstname", "имя", "name", "givenname", "given_name"}
LAST_NAMES  = {"last_name", "lastname", "фамилия", "surname", "familyname", "family_name"}
PHONES      = {"phone2", "телефон", "mobile", "mobile_phone", "тел"}
EMAILS      = {"email", "e-mail", "почта", "mail"}
ORGS        = {"org", "company", "компания", "организация"}
TITLES      = {"title", "должность"}
NOTES       = {"note", "notes", "заметки", "примечание"}

PHONE_SPLIT_REGEX = re.compile(r"[;\n\r\t,\/\|]+")  # разделители телефонов
ONLY_PLUS_DIGITS  = re.compile(r"[^\d+]")
INVALID_FN_CHARS  = re.compile(r"[^A-Za-z0-9А-Яа-яЁё _\-\.\(\)]")  # для имён файлов

def safe_filename(s: str, maxlen: int = 80) -> str:
    s = INVALID_FN_CHARS.sub("_", s).strip()
    s = re.sub(r"\s+", " ", s)
    return (s[:maxlen] or "contact").strip()

def pick_col(df, candidates):
    """Найти первую подходящую колонку из набора имён (без регистра/пробелов)."""
    norm = {str(c).lower().strip(): c for c in df.columns}
    for want in candidates:
        if want in norm:
            return norm[want]
    # мягкий матч: без пробелов
    for k, orig in norm.items():
        if k.replace(" ", "") in candidates:
            return orig
    return None

def normalize_phone(s: str) -> str:
    s = str(s or "").strip()
    if not s:
        return ""
    s = ONLY_PLUS_DIGITS.sub("", s)
    if s.startswith("00"):
        s = "+" + s[2:]
    return s

def split_phones(cell) -> list[str]:
    raw = str(cell or "").strip()
    if not raw:
        return []
    parts = [p.strip() for p in PHONE_SPLIT_REGEX.split(raw) if p.strip()]
    out, seen = [], set()
    for p in parts:
        n = normalize_phone(p)
        if n and n not in seen:
            seen.add(n)
            out.append(n)
    return out

def build_vcard_row(row, col_first, col_last, col_phone, col_email, col_org, col_title, col_note) -> tuple[str|None, str]:
    """Вернёт (vcard_text_or_None, display_name_for_filename)."""
    first = str(row.get(col_first, "")).strip() if col_first else ""
    last  = str(row.get(col_last,  "")).strip() if col_last  else ""
    full  = (f"{first} {last}".strip() or first or last).strip()
    phones = split_phones(row.get(col_phone, "")) if col_phone else []
    email  = str(row.get(col_email, "")).strip() if col_email else ""
    org    = str(row.get(col_org,   "")).strip() if col_org   else ""
    title  = str(row.get(col_title, "")).strip() if col_title else ""
    note   = str(row.get(col_note,  "")).strip().replace("\r", "") if col_note else ""

    if not (full or phones or email or org or title or note):
        return None, ""

    lines = ["BEGIN:VCARD", "VERSION:3.0"]
    if full:
        ln, fn = (last or ""), (first or "")
        lines.append(f"N:{ln};{fn};;;")
        lines.append(f"FN:{full}")
    if org:
        lines.append(f"ORG:{org}")
    if title:
        lines.append(f"TITLE:{title}")
    for p in phones:
        lines.append(f"TEL;TYPE=CELL:{p}")
    if email:
        lines.append(f"EMAIL:{email}")
    if note:
        lines.append(f"NOTE:{note}")
    lines.append("END:VCARD")
    return "\n".join(lines) + "\n", (full or (phones[0] if phones else "contact"))

def main():
    xlsx_path = BASE_DIR / INPUT_XLSX_NAME
    out_vcf_path = BASE_DIR / OUTPUT_VCF_NAME

    if not xlsx_path.exists():
        print(f"Файл не найден: {xlsx_path}")
        return

    try:
        df = pd.read_excel(xlsx_path, sheet_name=SHEET_NAME, dtype=str, engine="openpyxl")
    except Exception as e:
        print(f"Ошибка чтения XLSX: {e}")
        return

    df = df.fillna("").copy()
    if df.empty:
        print("В XLSX нет данных.")
        return

    # подрежем полностью пустые колонки
    non_empty_cols = [c for c in df.columns if not df[c].astype(str).str.strip().eq("").all()]
    df = df[non_empty_cols]
    if df.empty:
        print("Все колонки пустые.")
        return

    # нормализуем заголовки (только для поиска, сами значения не трогаем)
    df.columns = [str(c).strip() for c in df.columns]

    col_first = pick_col(df, FIRST_NAMES)
    col_last  = pick_col(df, LAST_NAMES)
    col_phone = pick_col(df, PHONES)
    col_email = pick_col(df, EMAILS)
    col_org   = pick_col(df, ORGS)
    col_title = pick_col(df, TITLES)
    col_note  = pick_col(df, NOTES)

    if not col_phone and not col_email:
        print("Не найдены колонки с телефонами/почтой. Ожидались: phone/телефон или email/почта (любая).")
        return

    # папка для индивидуальных карточек: <BASE_DIR>/<stem_of_xlsx>/
    per_contact_dir = BASE_DIR / xlsx_path.stem
    per_contact_dir.mkdir(parents=True, exist_ok=True)

    combined = []
    count = 0

    for idx, row in df.iterrows():
        vcard, disp = build_vcard_row(row, col_first, col_last, col_phone, col_email, col_org, col_title, col_note)
        if not vcard:
            continue
        combined.append(vcard)
        count += 1

        # имя файла контакта: 0001_Имя Фамилия.vcf
        safe_disp = safe_filename(disp)
        file_name = f"{count:04d}_{safe_disp}.vcf"
        (per_contact_dir / file_name).write_text(vcard, encoding="utf-8")

    if not combined:
        print("Нечего экспортировать (все строки пустые).")
        return

    out_vcf_path.write_text("".join(combined), encoding="utf-8")

    print("ГОТОВО ✅")
    print(f"- Общее VCF: {out_vcf_path}")
    print(f"- Индивидуальные карточки: {per_contact_dir}  (всего {count})")

if __name__ == "__main__":
    main()
