#!/usr/bin/env python3
"""
IMPORTADOR DEL CATÁLOGO WIX 2021 - FILTROS
Formato: Brand → Year → Model → Engine + filter columns
Páginas 77-687: Autos de pasajeros / camionetas ligeras
PDF: /tmp/catalogs/wix_2021.pdf
"""

import sqlite3
import re
import pypdf
from pathlib import Path

DB_PATH = Path(__file__).parent.parent / 'vehicle_database.db'
PDF_PATH = '/tmp/catalogs/wix_2021.pdf'

BRAND_HEADERS = {
    'ACURA', 'ALFA ROMEO', 'AM GENERAL', 'AMERICAN MOTORS', 'ASTON MARTIN',
    'ASUNA', 'AUDI', 'AUSTIN', 'AUSTIN HEALEY', 'AVANTI', 'BENTLEY', 'BMW',
    'BUICK', 'CADILLAC', 'CHECKER', 'CHEVROLET', 'CHRYSLER', 'DAEWOO',
    'DAIHATSU', 'DATSUN', 'DELOREAN', 'DODGE', 'EAGLE', 'FIAT', 'FORD',
    'FREIGHTLINER', 'GEO', 'GMC', 'HILLMAN', 'HONDA', 'HUMMER', 'HYUNDAI',
    'INFINITI', 'INTERNATIONAL', 'ISUZU', 'JAGUAR', 'JEEP', 'KIA',
    'LAFORZA', 'LAND ROVER', 'LEXUS', 'LINCOLN', 'LOTUS', 'MACK', 'MAZDA',
    'MERCEDES-BENZ', 'MERCURY', 'MERKUR', 'MINI', 'MITSUBISHI', 'MORGAN',
    'NISSAN', 'OLDSMOBILE', 'OPEL', 'PEUGEOT', 'PLYMOUTH', 'PONTIAC',
    'PORSCHE', 'RAM', 'RENAULT', 'ROLLS ROYCE', 'SAAB', 'SATURN', 'SCION',
    'SEAT', 'SHELBY', 'SMART', 'SRT', 'STUDEBAKER', 'SUBARU', 'SUNBEAM',
    'SUZUKI', 'TOYOTA', 'TRIUMPH', 'VOLKSWAGEN', 'VOLVO', 'WORKHORSE',
    'WORKHORSE CUSTOM CHASSIS',
}

ENGINE_RE = re.compile(r'^[VLH]\s*\d+\s+\d+\.\d+L', re.IGNORECASE)

FOOTER_MARKERS = [
    'Pass Car/Light Truck',
    'Year/Año/Année',
    'Model/Modelo/Modèle',
    'N/A = Not Available',
    'N/A = Non disponible',
    'N/A = No disponible',
    'Italicized Part Numbers',
    'Las piezas con números',
    'Les numéros de pièc',
    'Engine/Motor/Moteur',
    'Eng. Code',
    'Código de',
    'Code moteur',
    'Oil XP',
    'Aceite XP',
    'Cabina Aire',
    'Cabin Air XP',
    'Combustible',
    'Transmisión',
    'Carburant',
]

FILTER_GROUPS = {
    'oil': ('Oil Filters', 'Filtros de Aceite', 'Engine'),
    'air': ('Air Filters', 'Filtros de Aire', 'Engine'),
    'cabin_air': ('Cabin Air Filters', 'Filtros de Aire de Cabina', 'HVAC'),
    'fuel': ('Fuel Filters', 'Filtros de Combustible', 'Fuel System'),
    'transmission': ('Transmission Filters', 'Filtros de Transmisión', 'Transmission'),
}

TYPE_NAMES = {
    'oil': ('Oil Filter', 'Filtro de Aceite'),
    'oil_xp': ('Oil Filter XP', 'Filtro de Aceite XP'),
    'air': ('Air Filter', 'Filtro de Aire'),
    'air_xp': ('Air Filter XP', 'Filtro de Aire XP'),
    'cabin_air': ('Cabin Air Filter', 'Filtro de Aire de Cabina'),
    'cabin_air_xp': ('Cabin Air Filter XP', 'Filtro de Aire de Cabina XP'),
    'fuel': ('Fuel Filter', 'Filtro de Combustible'),
    'fuel_xp': ('Fuel Filter XP', 'Filtro de Combustible XP'),
    'transmission': ('Transmission Filter', 'Filtro de Transmisión'),
    'transmission_xp': ('Transmission Filter XP', 'Filtro de Transmisión XP'),
}

SKIP_VALUES = {'N/A', 'N/R', 'N/S', 'MT72', '-'}


def get_db():
    conn = sqlite3.connect(DB_PATH)
    conn.row_factory = sqlite3.Row
    return conn


def ensure_manufacturer(cursor, name, type_='aftermarket', quality='standard', country=None):
    cursor.execute("SELECT id FROM manufacturers WHERE UPPER(name) = UPPER(?)", (name,))
    row = cursor.fetchone()
    if row:
        return row['id']
    cursor.execute(
        "INSERT INTO manufacturers (name, type, quality_tier, country) VALUES (?, ?, ?, ?)",
        (name, type_, quality, country))
    return cursor.lastrowid


def ensure_brand(cursor, name):
    cursor.execute("SELECT id FROM brands WHERE UPPER(name) = UPPER(?)", (name,))
    row = cursor.fetchone()
    if row:
        return row['id']
    cursor.execute("INSERT INTO brands (name) VALUES (?)", (name,))
    return cursor.lastrowid


def ensure_model(cursor, brand_id, name):
    cursor.execute(
        "SELECT id FROM models WHERE brand_id = ? AND UPPER(name) = UPPER(?)",
        (brand_id, name))
    row = cursor.fetchone()
    if row:
        return row['id']
    cursor.execute("INSERT INTO models (brand_id, name) VALUES (?, ?)", (brand_id, name))
    return cursor.lastrowid


def ensure_year(cursor, year):
    cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
    row = cursor.fetchone()
    if row:
        return row['id']
    cursor.execute("INSERT INTO years (year) VALUES (?)", (year,))
    return cursor.lastrowid


def get_generic_engine(cursor):
    cursor.execute("SELECT id FROM engines WHERE name = 'Generic'")
    row = cursor.fetchone()
    if row:
        return row['id']
    cursor.execute("INSERT INTO engines (name, fuel_type) VALUES ('Generic', 'gasoline')")
    return cursor.lastrowid


def ensure_mye(cursor, model_id, year_id, engine_id=None):
    if engine_id:
        cursor.execute(
            "SELECT id FROM model_year_engine WHERE model_id = ? AND year_id = ? AND engine_id = ?",
            (model_id, year_id, engine_id))
    else:
        cursor.execute(
            "SELECT id FROM model_year_engine WHERE model_id = ? AND year_id = ?",
            (model_id, year_id))
    row = cursor.fetchone()
    if row:
        return row['id']
    if not engine_id:
        engine_id = get_generic_engine(cursor)
    cursor.execute(
        "INSERT INTO model_year_engine (model_id, year_id, engine_id) VALUES (?, ?, ?)",
        (model_id, year_id, engine_id))
    return cursor.lastrowid


def get_or_create_part(cursor, part_number, group_id, name, name_es, description):
    cursor.execute("SELECT id FROM parts WHERE oem_part_number = ?", (part_number,))
    row = cursor.fetchone()
    if row:
        return row['id'], False
    cursor.execute(
        "INSERT INTO parts (oem_part_number, name, name_es, group_id, description) VALUES (?, ?, ?, ?, ?)",
        (part_number, name, name_es, group_id, description))
    return cursor.lastrowid, True


def get_filter_group(cursor, filter_type):
    name_en, name_es, category_name = FILTER_GROUPS[filter_type]
    cursor.execute("SELECT id FROM part_groups WHERE name = ? LIMIT 1", (name_en,))
    row = cursor.fetchone()
    if row:
        return row['id']
    cursor.execute("SELECT id FROM part_categories WHERE name = ? LIMIT 1", (category_name,))
    cat = cursor.fetchone()
    if not cat:
        cursor.execute(
            "INSERT INTO part_categories (name, name_es) VALUES (?, ?)",
            (category_name, category_name))
        cat_id = cursor.lastrowid
    else:
        cat_id = cat['id']
    cursor.execute(
        "INSERT INTO part_groups (category_id, name, name_es) VALUES (?, ?, ?)",
        (cat_id, name_en, name_es))
    return cursor.lastrowid


# --- Part number extraction ---

def extract_wix_part(token):
    """Extract WIX part number from token, stripping footnote suffixes."""
    token = token.strip().rstrip('.')
    if not token or token in SKIP_VALUES:
        return None

    # XP variants: 5digits+XP
    xp_match = re.match(r'^(\d{5}XP)', token)
    if xp_match:
        return xp_match.group(1)

    # Alpha-prefixed parts
    wl = re.match(r'^(WL\d{4,6})', token)
    if wl:
        return wl.group(1)
    wa = re.match(r'^(WA\d{4,5})', token)
    if wa:
        return wa.group(1)
    wp = re.match(r'^(WP\d{4,5})', token)
    if wp:
        return wp.group(1)
    wf = re.match(r'^(WF\d{4})', token)
    if wf:
        return wf.group(1)

    # Numeric 5-digit WIX parts
    num = re.match(r'^(\d{5})', token)
    if num:
        pn = num.group(1)
        p2 = pn[:2]
        if p2 in ('51', '57', '42', '43', '44', '45', '46', '47', '48', '49',
                   '24', '33', '58'):
            return pn

    return None


def classify_filter(pn):
    """Classify a WIX part number by filter type."""
    if not pn:
        return None
    if pn.endswith('XP'):
        base_type = classify_filter(pn[:-2])
        return f"{base_type}_xp" if base_type else None
    if pn.startswith('WL'):
        return 'oil'
    if pn.startswith('WA'):
        return 'air'
    if pn.startswith('WP'):
        return 'cabin_air'
    if pn.startswith('WF'):
        return 'fuel'
    if re.match(r'^5[17]\d{3}$', pn):
        return 'oil'
    if re.match(r'^4[2-9]\d{3}$', pn):
        return 'air'
    if re.match(r'^24\d{3}$', pn):
        return 'cabin_air'
    if re.match(r'^33\d{3}$', pn):
        return 'fuel'
    if re.match(r'^58\d{3}$', pn):
        return 'transmission'
    return None


def extract_parts_from_tokens(tokens):
    """Extract all unique WIX part numbers from tokens."""
    parts = []
    seen = set()
    for token in tokens:
        pn = extract_wix_part(token)
        if pn and pn not in seen:
            ftype = classify_filter(pn)
            if ftype:
                parts.append((pn, ftype))
                seen.add(pn)
    return parts


# --- Line classification ---

def is_footer_line(line):
    return any(m in line for m in FOOTER_MARKERS)


def is_continuation(line):
    """Check if line continues engine data (not a new model/brand/year)."""
    tokens = line.split()
    if not tokens:
        return False
    first = tokens[0]
    if first in ('Electric/Gas', 'Turbo', 'Diesel', 'Hybrid', 'O'):
        return True
    if first.startswith('N/'):
        return True
    if first.startswith('MT'):
        return True
    if re.match(r'^(WL|WA|WP|WF)\d', first):
        return True
    if re.match(r'^\d{5}', first):
        return True
    if first == '-':
        return True
    # Single/double digit + more tokens with part numbers
    if re.match(r'^\d{1,2}$', first) and len(tokens) > 1:
        for t in tokens[1:4]:
            if extract_wix_part(t):
                return True
    return False


# --- PDF parsing ---

def parse_wix_pdf(pdf_path):
    """Parse WIX 2021 catalog pages 77-687."""
    pdf = pypdf.PdfReader(pdf_path)
    entries = []

    current_brand = None
    current_year = None
    current_model = None
    current_tokens = []

    def flush_engine():
        nonlocal current_tokens
        if current_brand and current_year and current_model and current_tokens:
            parts = extract_parts_from_tokens(current_tokens)
            if parts:
                entries.append({
                    'brand': current_brand,
                    'model': current_model,
                    'year': current_year,
                    'parts': parts,
                })
        current_tokens = []

    total_pages = min(len(pdf.pages), 687)
    for page_num in range(76, total_pages):
        if (page_num - 76) % 50 == 0:
            print(f"      Procesando página {page_num + 1}/{total_pages}...")

        text = pdf.pages[page_num].extract_text()
        if not text:
            continue

        for line in text.split('\n'):
            line = line.strip()
            if not line:
                continue

            # Skip footer lines
            if is_footer_line(line):
                continue

            # Clean continuation markers
            clean = re.sub(r"\s*\(Cont'd/Suite\)\s*", '', line).strip()
            if not clean:
                continue

            # Brand header
            upper_clean = clean.upper()
            if upper_clean in BRAND_HEADERS:
                flush_engine()
                current_brand = clean
                current_year = None
                current_model = None
                continue

            # Year
            year_match = re.match(r'^(\d{4})$', clean)
            if year_match:
                y = int(year_match.group(1))
                if 1940 <= y <= 2025:
                    flush_engine()
                    current_year = y
                    current_model = None
                    continue

            if not current_brand or not current_year:
                continue

            # Engine line
            if ENGINE_RE.match(clean):
                flush_engine()
                current_tokens = clean.split()
                continue

            # Continuation of engine data
            if current_tokens and is_continuation(clean):
                current_tokens.extend(clean.split())
                continue

            # Model name (must contain alpha characters)
            if re.search(r'[A-Za-z]', clean):
                flush_engine()
                current_model = clean
                continue

    flush_engine()
    return entries


def main():
    print("=" * 70)
    print("IMPORTADOR - CATÁLOGO WIX 2021")
    print("=" * 70)

    print(f"\n[1/6] Leyendo PDF: {PDF_PATH}")
    entries = parse_wix_pdf(PDF_PATH)
    print(f"      Entradas parseadas: {len(entries)}")

    unique_parts = {}
    for entry in entries:
        for pn, ftype in entry['parts']:
            if pn not in unique_parts:
                unique_parts[pn] = ftype

    unique_brands = set(e['brand'] for e in entries)
    print(f"      Partes únicas: {len(unique_parts)}")
    print(f"      Marcas de vehículos: {len(unique_brands)}")

    conn = get_db()
    cursor = conn.cursor()

    print("\n[2/6] Creando fabricante WIX...")
    wix_mfr_id = ensure_manufacturer(cursor, 'WIX', 'aftermarket', 'premium', 'USA')
    print(f"      WIX manufacturer_id: {wix_mfr_id}")

    print("\n[3/6] Creando partes de filtros...")
    group_ids = {}
    for ftype in FILTER_GROUPS:
        group_ids[ftype] = get_filter_group(cursor, ftype)
        group_ids[f"{ftype}_xp"] = group_ids[ftype]

    part_ids = {}
    parts_created = 0
    for pn, ftype in sorted(unique_parts.items()):
        gid = group_ids.get(ftype)
        if not gid:
            continue
        name_en, name_es = TYPE_NAMES.get(ftype, ('Filter', 'Filtro'))
        part_id, created = get_or_create_part(
            cursor, pn, gid,
            f"{name_en} {pn}", f"{name_es} {pn}",
            f"WIX {name_en}")
        part_ids[pn] = part_id
        if created:
            parts_created += 1

    print(f"      Partes creadas: {parts_created}")
    print(f"      Partes existentes: {len(unique_parts) - parts_created}")

    print("\n[4/6] Creando vehículos y fitments...")
    vehicles_created = 0
    fitments_created = 0
    mye_cache = {}

    for i, entry in enumerate(entries):
        if i % 5000 == 0 and i > 0:
            print(f"      Procesando entrada {i}/{len(entries)}...")

        cache_key = (entry['brand'].upper(), entry['model'].upper(), entry['year'])
        if cache_key not in mye_cache:
            brand_id = ensure_brand(cursor, entry['brand'])
            model_id = ensure_model(cursor, brand_id, entry['model'])
            year_id = ensure_year(cursor, entry['year'])

            cursor.execute("""
                SELECT mye.id FROM model_year_engine mye
                JOIN models m ON mye.model_id = m.id
                JOIN brands b ON m.brand_id = b.id
                JOIN years y ON mye.year_id = y.id
                WHERE UPPER(b.name) = UPPER(?) AND UPPER(m.name) = UPPER(?) AND y.year = ?
                LIMIT 1
            """, (entry['brand'], entry['model'], entry['year']))
            existing = cursor.fetchone()

            if existing:
                mye_cache[cache_key] = existing['id']
            else:
                mye_id = ensure_mye(cursor, model_id, year_id)
                mye_cache[cache_key] = mye_id
                vehicles_created += 1

        mye_id = mye_cache[cache_key]

        for pn, ftype in entry['parts']:
            part_id = part_ids.get(pn)
            if not part_id:
                continue

            cursor.execute(
                "SELECT id FROM vehicle_parts WHERE model_year_engine_id = ? AND part_id = ?",
                (mye_id, part_id))
            if not cursor.fetchone():
                notes = f"Catálogo WIX 2021 - {ftype.replace('_', ' ').upper()}"
                cursor.execute(
                    "INSERT INTO vehicle_parts (model_year_engine_id, part_id, quantity_required, fitment_notes) VALUES (?, ?, 1, ?)",
                    (mye_id, part_id, notes))
                fitments_created += 1

    print(f"      Vehículos creados: {vehicles_created}")
    print(f"      Fitments creados: {fitments_created}")

    print("\n[5/6] Creando referencias cruzadas...")
    xrefs_created = 0
    wix_part_id_set = set(part_ids.values())

    for i, (pn, part_id) in enumerate(part_ids.items()):
        if i % 200 == 0 and i > 0:
            print(f"      Procesando cross-ref {i}/{len(part_ids)}...")

        cursor.execute("""
            SELECT DISTINCT p2.id, p2.oem_part_number
            FROM vehicle_parts vp1
            JOIN vehicle_parts vp2 ON vp1.model_year_engine_id = vp2.model_year_engine_id
            JOIN parts p2 ON vp2.part_id = p2.id
            WHERE vp1.part_id = ?
              AND p2.id != ?
              AND p2.group_id = (SELECT group_id FROM parts WHERE id = ?)
            LIMIT 50
        """, (part_id, part_id, part_id))

        for row in cursor.fetchall():
            if row['id'] in wix_part_id_set:
                continue

            cursor.execute(
                "SELECT id FROM part_cross_references WHERE part_id = ? AND cross_reference_number = ?",
                (part_id, row['oem_part_number']))
            if not cursor.fetchone():
                cursor.execute(
                    "INSERT INTO part_cross_references (part_id, cross_reference_number, reference_type, source) VALUES (?, ?, 'interchange', 'WIX 2021 Catalog')",
                    (part_id, row['oem_part_number']))
                xrefs_created += 1

            cursor.execute(
                "SELECT id FROM part_cross_references WHERE part_id = ? AND cross_reference_number = ?",
                (row['id'], pn))
            if not cursor.fetchone():
                cursor.execute(
                    "INSERT INTO part_cross_references (part_id, cross_reference_number, reference_type, source) VALUES (?, ?, 'interchange', 'WIX 2021 Catalog')",
                    (row['id'], pn))
                xrefs_created += 1

    print(f"      Cross-refs creadas: {xrefs_created}")

    conn.commit()
    conn.close()

    print("\n" + "=" * 70)
    print("IMPORTACIÓN WIX COMPLETADA")
    print("=" * 70)
    print(f"""
RESUMEN:
  - Partes creadas:        {parts_created:,}
  - Vehículos creados:     {vehicles_created:,}
  - Fitments creados:      {fitments_created:,}
  - Cross-refs creadas:    {xrefs_created:,}
""")


if __name__ == '__main__':
    main()
