<?php
declare(strict_types=1);

/**
 * RCIC Auto-Matcher
 *
 * Logik:
 *   1. Liest form_data des Klienten
 *   2. Extrahiert bevorzugte Provinzen (mehrere Feldnamen werden probiert)
 *   3. Findet aktive RCICs in diesen Provinzen, Deutsch bevorzugt
 *   4. Sortiert nach: Provinz-Match → Sprache → sort_order
 *   5. Bei zu wenig Treffern: aufgefüllt aus anderen Provinzen
 *   6. Schreibt Zuordnungen idempotent in client_rcic_zuordnung
 *
 * Aufrufbar von:
 *   - capture-order.php (nach erfolgreichem Capture)
 *   - hq/release-client.php (vorab bei Freigabe — optional)
 *   - HQ-Tooling für manuelles Re-Matching
 *
 * Schreibt KEIN HTML, gibt nur strukturierte Daten zurück.
 *
 * Benötigt: PDO mit Zugriff auf clients, rcic_consultants, client_rcic_zuordnung
 */

/**
 * Mapping zwischen verschiedenen Schreibweisen kanadischer Provinzen
 * und der kanonischen Form, wie sie in rcic_consultants.province steht.
 */
const C2C_PROVINCE_CANON = [
    'ontario'              => 'Ontario',
    'on'                   => 'Ontario',
    'bc'                   => 'BC',
    'british columbia'     => 'BC',
    'britisch kolumbien'   => 'BC',
    'britisch-kolumbien'   => 'BC',
    'alberta'              => 'Alberta',
    'ab'                   => 'Alberta',
    'quebec'               => 'Quebec',
    'québec'               => 'Quebec',
    'qc'                   => 'Quebec',
    'nova scotia'          => 'Nova Scotia',
    'neuschottland'        => 'Nova Scotia',
    'ns'                   => 'Nova Scotia',
    'manitoba'             => 'Manitoba',
    'mb'                   => 'Manitoba',
    'saskatchewan'         => 'Saskatchewan',
    'sk'                   => 'Saskatchewan',
    'new brunswick'        => 'NB',
    'neubraunschweig'      => 'NB',
    'nb'                   => 'NB',
    'prince edward island' => 'PEI',
    'pei'                  => 'PEI',
    'pe'                   => 'PEI',
    'newfoundland'         => 'Newfoundland',
    'newfoundland and labrador' => 'Newfoundland',
    'nl'                   => 'Newfoundland',
    'yukon'                => 'Yukon',
    'yt'                   => 'Yukon',
    'nwt'                  => 'Northwest Territories',
    'northwest territories' => 'Northwest Territories',
    'nunavut'              => 'Nunavut',
    'nu'                   => 'Nunavut',
];

/**
 * Sucht im form_data rekursiv nach Provinz-bezogenen Feldern und gibt
 * eine deduplizierte, normalisierte Liste kanadischer Provinzen zurück.
 *
 * Erkannt werden Feldnamen, die "provinz", "province", "wunschprovinz"
 * oder "preferred_province" enthalten (case-insensitive).
 *
 * @param array $formData Decodiertes form_data JSON
 * @return string[] Liste kanonischer Provinznamen
 */
function c2c_extract_preferred_provinces(array $formData): array
{
    $found = [];

    $walker = function ($node, $parentKey = '') use (&$walker, &$found) {
        if (is_array($node)) {
            foreach ($node as $key => $value) {
                $walker($value, (string)$key);
            }
            return;
        }

        $keyLower = strtolower($parentKey);
        $isProvinceField = (
            str_contains($keyLower, 'provinz') ||
            str_contains($keyLower, 'province')
        );

        if (!$isProvinceField) {
            return;
        }

        if (is_string($node) && $node !== '') {
            // Feld kann eine einzelne Provinz oder eine Komma-/Semikolon-Liste sein
            foreach (preg_split('/[,;|\/]+/', $node) as $part) {
                $canon = c2c_canonicalize_province($part);
                if ($canon !== null) $found[] = $canon;
            }
        }
    };

    $walker($formData);

    return array_values(array_unique($found));
}

/**
 * Normalisiert einen Provinz-String auf die kanonische Form.
 * Gibt null zurück, wenn nichts erkannt wurde.
 */
function c2c_canonicalize_province(string $raw): ?string
{
    $key = strtolower(trim($raw));
    if ($key === '') return null;

    if (isset(C2C_PROVINCE_CANON[$key])) {
        return C2C_PROVINCE_CANON[$key];
    }

    // Fallback: enthält der String eine bekannte Provinz?
    foreach (C2C_PROVINCE_CANON as $alias => $canon) {
        if (strlen($alias) >= 3 && str_contains($key, $alias)) {
            return $canon;
        }
    }

    return null;
}

/**
 * Holt RCICs für einen Klienten basierend auf form_data.
 *
 * Sortierung:
 *   1. Provinz-Match (1 = Match, 0 = kein Match)
 *   2. Sprache Deutsch (1 = Deutsch im languages-Feld, 0 = nicht)
 *   3. sort_order ASC
 *   4. id ASC (deterministisch)
 *
 * @return array[] Liste RCIC-Rows + zusätzliches Feld 'match_reason'
 */
function c2c_find_matching_rcics(PDO $pdo, array $formData, int $limit = 3): array
{
    $provinces = c2c_extract_preferred_provinces($formData);

    // Provinz-Filter dynamisch aufbauen
    if (count($provinces) > 0) {
        $placeholders = implode(',', array_fill(0, count($provinces), '?'));
        $provinceMatchExpr = "CASE WHEN province IN ($placeholders) THEN 1 ELSE 0 END";
        $params = $provinces;
    } else {
        $provinceMatchExpr = "0";
        $params = [];
    }

    $sql = "
        SELECT
            id, name, firm, city, province, languages, specialties,
            email, website, rcic_number, sort_order,
            $provinceMatchExpr AS province_match,
            CASE
                WHEN languages LIKE '%Deutsch%' OR languages LIKE '%German%' THEN 1
                ELSE 0
            END AS speaks_german
        FROM rcic_consultants
        WHERE active = 1
        ORDER BY province_match DESC, speaks_german DESC, sort_order ASC, id ASC
        LIMIT " . (int)$limit;

    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);
    $rows = $stmt->fetchAll();

    // Pro Treffer eine kurze Begründung anhängen (für client_rcic_zuordnung.match_reason)
    foreach ($rows as &$row) {
        $reasons = [];
        if ((int)$row['province_match'] === 1) {
            $reasons[] = 'Provinz ' . $row['province'];
        }
        if ((int)$row['speaks_german'] === 1) {
            $reasons[] = 'Deutsch';
        }
        if (empty($reasons)) {
            $reasons[] = 'Auffüllung';
        }
        $row['match_reason'] = implode(', ', $reasons);
    }
    unset($row);

    return $rows;
}

/**
 * Schreibt RCIC-Zuordnungen für einen Klienten in client_rcic_zuordnung.
 *
 * Idempotent für 'auto'-Zuordnungen: löscht zuerst alle bestehenden
 * Auto-Zuordnungen für diesen Klienten, schreibt dann neu.
 * Manuelle Zuordnungen ('christian' etc.) bleiben unangetastet.
 *
 * @param array[]  $rcics       Liste RCIC-Rows wie von c2c_find_matching_rcics
 * @param string   $assignedBy  'auto' | 'christian' | <username>
 *
 * @return int Anzahl geschriebener Zuordnungen
 */
function c2c_assign_rcics_to_client(
    PDO $pdo,
    int $clientId,
    array $rcics,
    string $assignedBy = 'auto'
): int {
    if (count($rcics) === 0) return 0;

    $pdo->beginTransaction();
    try {
        // Bei Auto-Match: alte Auto-Zuordnungen löschen, manuelle behalten
        if ($assignedBy === 'auto') {
            $pdo->prepare(
                'DELETE FROM client_rcic_zuordnung
                 WHERE client_id = ? AND assigned_by = "auto"'
            )->execute([$clientId]);
        }

        $insert = $pdo->prepare(
            'INSERT IGNORE INTO client_rcic_zuordnung
                (client_id, rcic_id, sort_order, assigned_by, match_reason)
             VALUES (?, ?, ?, ?, ?)'
        );

        $written = 0;
        foreach ($rcics as $i => $rcic) {
            $insert->execute([
                $clientId,
                (int)$rcic['id'],
                $i, // Reihenfolge wie aus dem Matcher
                $assignedBy,
                $rcic['match_reason'] ?? null,
            ]);
            $written += $insert->rowCount();
        }

        $pdo->commit();
        return $written;

    } catch (Throwable $e) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        throw $e;
    }
}

/**
 * Komfort-Funktion: One-Shot-Aufruf
 *   1. Liest form_data des Klienten
 *   2. Findet passende RCICs
 *   3. Schreibt sie als Auto-Zuordnung
 *
 * @return array {written: int, rcics: array[], provinces_detected: string[]}
 */
function c2c_auto_match_for_client(PDO $pdo, int $clientId, int $limit = 3): array
{
    $stmt = $pdo->prepare('SELECT form_data FROM clients WHERE id = ? LIMIT 1');
    $stmt->execute([$clientId]);
    $row = $stmt->fetch();

    if (!$row) {
        throw new RuntimeException("Klient $clientId nicht gefunden");
    }

    $formData = [];
    if (!empty($row['form_data'])) {
        $decoded = json_decode($row['form_data'], true);
        if (is_array($decoded)) $formData = $decoded;
    }

    $rcics = c2c_find_matching_rcics($pdo, $formData, $limit);
    $written = c2c_assign_rcics_to_client($pdo, $clientId, $rcics, 'auto');

    return [
        'written'            => $written,
        'rcics'              => $rcics,
        'provinces_detected' => c2c_extract_preferred_provinces($formData),
    ];
}

/**
 * Liest die einem Klienten zugeordneten RCICs (für Customer-View).
 * Reihenfolge: sort_order der Zuordnung, dann Name.
 */
function c2c_load_assigned_rcics(PDO $pdo, int $clientId): array
{
    $stmt = $pdo->prepare(
        'SELECT
            r.id, r.name, r.firm, r.city, r.province,
            r.languages, r.specialties, r.email, r.website, r.rcic_number,
            z.match_reason, z.assigned_by
         FROM client_rcic_zuordnung z
         INNER JOIN rcic_consultants r ON r.id = z.rcic_id
         WHERE z.client_id = ?
         ORDER BY z.sort_order ASC, r.name ASC'
    );
    $stmt->execute([$clientId]);
    return $stmt->fetchAll();
}
