<?php
// siigo/scripts/sync_terceros.php

require_once __DIR__ . '/../config/config.php';
require_once __DIR__ . '/../lib/Client.php';


// ——————————————————————————
// 1) Conexión MySQL
// ——————————————————————————
$mysqli = new mysqli('localhost', 'ndconsulta', 'Nitro2021', 'db_compranet', 3306);
if ($mysqli->connect_error) {
    die("Error MySQL: " . $mysqli->connect_error);
}
$mysqli->set_charset('utf8');

// ——————————————————————————
// 2) Obtenemos la primera página de terceros
// ——————————————————————————
$client = new SiigoClient();
$perPage = 25;
$page    = 1;

do {
    // 2.1) Traer la página actual
    $resp = safeGet($client, 'customers', [
        'page'      => $page,
        'page_size' => $perPage
    ]);
    $terceros  = $resp['results']   ?? [];
    $pagination = $resp['pagination'] ?? [];
    $total     = $pagination['total_results'] ?? 0;
    $pageSize  = $pagination['page_size']     ?? $perPage;

    if (empty($terceros)) {
        break; // ya no quedan más registros
    }

    echo "Procesando página {$page} de " . ceil($total / $pageSize) . " (" . count($terceros) . " terceros)\n";

    // 2.2) Por cada tercero de esta página, reaplicar tu lógica original:
    foreach ($terceros as $c) {
        $siigoId   = $c['id'];
        // 3.1) Si ya existe, saltamos
        $stmt = $mysqli->prepare("SELECT id FROM tb_terceros WHERE siigo_id = ?");
        $stmt->bind_param('s', $siigoId);
        $stmt->execute();
        $stmt->store_result();
        if ($stmt->num_rows > 0) {
            echo "Tercero {$siigoId} ya existe, se omite.\n";
            $stmt->close();
            continue;
        }
        $stmt->close();

        // ——————————————————————————
        // 3.2) Roles y tipos
        // ——————————————————————————
        // 3.2) Roles y tipos
        $rolId      = getOrCreateRol($mysqli, $c['type']);
        $tipoTercId = getOrCreateTipoTercero($mysqli, $c['person_type']);

        // id_type puede no venir, normalizamos:
        $idType      = $c['id_type'] ?? [];
        $idTypeCode  = $idType['code'] ?? 'NA';               // “NA” o el código por defecto que uses
        $idTypeName  = $idType['name'] ?? 'No especificado';  // fallback para el nombre
        $tipoDocId   = getOrCreateTipoDocumento(
            $mysqli,
            $idTypeCode,
            $idTypeName
        );


        // ——————————————————————————
        // 3.3) Responsabilidades fiscales
        // ——————————————————————————
        $fiscalRespIds = [];
        foreach ($c['fiscal_responsibilities'] as $fr) {
            $fiscalRespIds[] = getOrCreateFiscalResponsabilidad(
                $mysqli,
                $fr['code'],
                $fr['name']
            );
        }

        // ——————————————————————————
        // 3.4) País, departamento y ciudad
        // ——————————————————————————
        $addr    = $c['address'];
        $cityObj = $addr['city'];
        $paisId  = getOrCreatePais(
            $mysqli,
            strtoupper($cityObj['country_code']),
            $cityObj['country_name']
        );
        $depId   = getOrCreateDepartamento(
            $mysqli,
            $cityObj['state_code'],
            $cityObj['state_name'],
            $paisId
        );
        $ciudadId = getOrCreateCiudad(
            $mysqli,
            $cityObj['city_code'],
            $cityObj['city_name'],
            $depId
        );

        $telefono = '';
        // 1) ¿viene en "phones" y no es el placeholder "0000000"?
        if (!empty($c['phones'][0]['number']) && $c['phones'][0]['number'] !== '0000000') {
            $p = $c['phones'][0];
        }
        // 2) Si no, ¿viene en "contacts"[0]["phone"] válido?
        elseif (
            !empty($c['contacts'][0]['phone']['number'])
            && $c['contacts'][0]['phone']['number'] !== '0000000'
        ) {
            $p = $c['contacts'][0]['phone'];
        }
        // 3) Si encontramos un teléfono válido, formateamos:
        if (isset($p)) {
            $indic = $p['indicative'] ?? '';
            $num   = $p['number'];
            $ext   = $p['extension'] ?? '';

            // Base del teléfono
            $telefono = trim(
                ($indic ? "({$indic}) " : '') .
                    $num
            );

            // Solo añadimos " ext XXX" si hay extensión y NO es todo ceros
            if ($ext !== '' && !preg_match('/^0+$/', $ext)) {
                $telefono .= " ext {$ext}";
            }
        }
        // ——————————————————————————
        // 3.5) Usuario y contacto
        // ——————————————————————————
        if ($c['person_type'] === 'Company') {
            $firstName = implode(' ', $c['name']);
            $lastName  = '';
        } else {
            $firstName = $c['name'][0] ?? '';
            $lastName  = $c['name'][1] ?? '';
        }
        $email = $c['contacts'][0]['email'] ?? '';
        if (!$email) {
            // 1) Concatenar nombre y apellido
            $base = "{$firstName}{$lastName}";
            // 2) Pasar todo a minúsculas
            $base = strtolower($base);
            // 3) Eliminar TODO lo que no sea letra o número
            $base = preg_replace('/[^a-z0-9]/', '', $base);
            // 4) Formar el email
            $email = $base . '@tercerosiigo.com';
        }
        $userId = getOrCreateUsuario(
            $mysqli,
            $firstName,
            $lastName,
            $email,
            $ciudadId,
            $telefono
        );

        // ——————————————————————————
        // 3.6) Direcciones de usuario
        // ——————————————————————————
        $direccion   = $addr['address'];
        // ——————————————————————————
        // Extraer teléfono: prioriza "phones" y si no, "contacts"
        // ——————————————————————————


        $idDireccion = getOrCreateUsuarioDireccion(
            $mysqli,
            $userId,
            $firstName,
            $lastName,
            ($c['person_type'] === 'Company' ? implode(' ', $c['name']) : null),
            $direccion,
            $telefono,
            $email,
            $ciudadId,
            $c['identification']
        );

        // ——————————————————————————
        // 3.7) Insertar tercero
        // ——————————————————————————
        $idRegimen   = ($c['person_type'] === 'Company' ? 1 : 2);
        $noDocumento = $c['identification'];
        $dv = (isset($c['check_digit']) && is_numeric($c['check_digit']))
            ? (int)$c['check_digit']
            : NULL;
        $nombre      = $firstName;
        $apellido    = $lastName;
        $razonSocial = ($c['person_type'] === 'Company' ? implode(' ', $c['name']) : null);

        $stmt = $mysqli->prepare("
        INSERT INTO tb_terceros
          (idTipoTercero, idRegimen, idRol, idUsuario, idTipoDocumento,
           idDireccion, noDocumento, dv, nombre, apellido,
           razonSocial, emailFactura, siigo_id)
        VALUES
          (?,?,?,?,?,?,?,?,?,?,?,?,?)
    ");
        $stmt->bind_param(
            'iiiiiisssssss',
            $tipoTercId,
            $idRegimen,
            $rolId,
            $userId,
            $tipoDocId,
            $idDireccion,
            $noDocumento,
            $dv,
            $nombre,
            $apellido,
            $razonSocial,
            $email,
            $siigoId
        );
        $stmt->execute();
        $terceroId = $stmt->insert_id;
        $stmt->close();

        // ——————————————————————————
        // 3.8) Mapear responsabilidades fiscales
        // ——————————————————————————
        foreach ($fiscalRespIds as $frId) {
            $stmt = $mysqli->prepare("
            INSERT INTO tb_terceros_responsabilidad_fiscal
              (idTercero, idResponsabilidadFiscal)
            VALUES (?,?)
        ");
            $stmt->bind_param('ii', $terceroId, $frId);
            $stmt->execute();
            $stmt->close();
        }

        echo "Importado tercero {$siigoId}\n";
    }

    $page++;
} while (($page - 1) * $perPage < $total);
echo "Importación de terceros completada.\n";

// ——————————————————————————
// Funciones auxiliares
// ——————————————————————————

function getOrCreateRol($db, $code)
{
    $stmt = $db->prepare("SELECT id FROM tb_rol_tercero WHERE siigo_code = ?");
    $stmt->bind_param('s', $code);
    $stmt->execute();
    $stmt->bind_result($id);
    if ($stmt->fetch()) {
        $stmt->close();
        return $id;
    }
    $stmt->close();
    $stmt = $db->prepare("
        INSERT INTO tb_rol_tercero (siigo_code, nombre)
        VALUES (?,?)
    ");
    $stmt->bind_param('ss', $code, $code);
    $stmt->execute();
    $newId = $stmt->insert_id;
    $stmt->close();
    return $newId;
}

function getOrCreateTipoTercero($db, $personType)
{
    $stmt = $db->prepare("SELECT id FROM tb_tipo_tercero WHERE person_type = ?");
    $stmt->bind_param('s', $personType);
    $stmt->execute();
    $stmt->bind_result($id);
    if ($stmt->fetch()) {
        $stmt->close();
        return $id;
    }
    $stmt->close();
    $stmt = $db->prepare("
        INSERT INTO tb_tipo_tercero (person_type)
        VALUES (?)
    ");
    $stmt->bind_param('s', $personType);
    $stmt->execute();
    $newId = $stmt->insert_id;
    $stmt->close();
    return $newId;
}

function getOrCreateTipoDocumento($db, $code, $name)
{
    $stmt = $db->prepare("SELECT id FROM tb_tipo_documento WHERE siigo_code = ?");
    $stmt->bind_param('s', $code);
    $stmt->execute();
    $stmt->bind_result($id);
    if ($stmt->fetch()) {
        $stmt->close();
        return $id;
    }
    $stmt->close();
    $stmt = $db->prepare("
        INSERT INTO tb_tipo_documento (siigo_code, nombre)
        VALUES (?,?)
    ");
    $stmt->bind_param('ss', $code, $name);
    $stmt->execute();
    $newId = $stmt->insert_id;
    $stmt->close();
    return $newId;
}

function getOrCreateFiscalResponsabilidad($db, $code, $name)
{
    $stmt = $db->prepare("SELECT id FROM tb_responsabilidad_fiscal WHERE siigo_code = ?");
    $stmt->bind_param('s', $code);
    $stmt->execute();
    $stmt->bind_result($id);
    if ($stmt->fetch()) {
        $stmt->close();
        return $id;
    }
    $stmt->close();
    $stmt = $db->prepare("
        INSERT INTO tb_responsabilidad_fiscal (siigo_code, nombre)
        VALUES (?,?)
    ");
    $stmt->bind_param('ss', $code, $name);
    $stmt->execute();
    $newId = $stmt->insert_id;
    $stmt->close();
    return $newId;
}

function getOrCreatePais($db, $code, $name)
{
    $stmt = $db->prepare("SELECT id FROM tb_paises WHERE code = ?");
    $stmt->bind_param('s', $code);
    $stmt->execute();
    $stmt->bind_result($id);
    if ($stmt->fetch()) {
        $stmt->close();
        return $id;
    }
    $stmt->close();
    $stmt = $db->prepare("
        INSERT INTO tb_paises (code, nombre)
        VALUES (?,?)
    ");
    $stmt->bind_param('ss', $code, $name);
    $stmt->execute();
    $newId = $stmt->insert_id;
    $stmt->close();
    return $newId;
}

function getOrCreateDepartamento($db, $code, $name, $paisId)
{
    $stmt = $db->prepare("SELECT id FROM tb_departamentos WHERE state_code = ?");
    $stmt->bind_param('s', $code);
    $stmt->execute();
    $stmt->bind_result($id);
    if ($stmt->fetch()) {
        $stmt->close();
        return $id;
    }
    $stmt->close();
    $stmt = $db->prepare("
        INSERT INTO tb_departamentos (state_code, nombre, idPais)
        VALUES (?,?,?)
    ");
    $stmt->bind_param('ssi', $code, $name, $paisId);
    $stmt->execute();
    $newId = $stmt->insert_id;
    $stmt->close();
    return $newId;
}

function getOrCreateCiudad($db, $code, $name, $depId)
{
    $stmt = $db->prepare("SELECT id FROM tb_ciudades WHERE city_code = ?");
    $stmt->bind_param('s', $code);
    $stmt->execute();
    $stmt->bind_result($id);
    if ($stmt->fetch()) {
        $stmt->close();
        return $id;
    }
    $stmt->close();
    $stmt = $db->prepare("
        INSERT INTO tb_ciudades (city_code, nombre, idDepartamento)
        VALUES (?,?,?)
    ");
    $stmt->bind_param('ssi', $code, $name, $depId);
    $stmt->execute();
    $newId = $stmt->insert_id;
    $stmt->close();
    return $newId;
}


/**
 * Normaliza un email: minúsculas, quita todo lo que no sea a–z o 0–9 en la parte local
 */
function normalizeEmail(string $email): string
{
    $email  = strtolower($email);
    // Separa local@dominio (si falta dominio, usa tercerosiigo.com)
    list($local, $domain) = array_pad(explode('@', $email, 2), 2, 'tercerosiigo.com');
    // Elimina caracteres que no sean letras ni números
    $local = preg_replace('/[^a-z0-9]/', '', $local);
    return $local . '@' . $domain;
}

function normalizePhone(string $phone): string
{
    // quitar todo excepto dígitos y letras 'e','x','t'
    // asumimos que $phone ya viene formateado como "(057) 3173672133 ext 113"
    // si no, aplica esta limpieza básica:
    if (!$phone) {
        return '';
    }
    // Extrae dígitos
    preg_match_all('/\d+/', $phone, $m);
    $all = implode('', $m[0]);
    // si sólo ceros o longitud ≤ 2, lo descartamos
    if (preg_match('/^0+$/', $all) || strlen($all) <= 2) {
        return '';
    }
    // deja el phone tal cual (formateado previamente)
    return $phone;
}
function getOrCreateUsuario($db, $first, $last, $email, $ciudadId, $telefono)
{
    // 1) normalizar email y teléfono
    $emailNorm = normalizeEmail($email);
    $telNorm   = normalizePhone($telefono);

    // 2) buscar por email (clave única)
    $stmt = $db->prepare("SELECT id FROM tb_usuarios WHERE email = ?");
    $stmt->bind_param('s', $emailNorm);
    $stmt->execute();
    $stmt->bind_result($id);
    if ($stmt->fetch()) {
        $stmt->close();
        return $id;
    }
    $stmt->close();

    // 3) insertar nuevo usuario, incluyendo teléfono si existe
    $stmt = $db->prepare("
        INSERT INTO tb_usuarios
          (nombre, apellido, email, idCiudad, telefono)
        VALUES (?,?,?,?,?)
    ");
    $stmt->bind_param(
        'sssis',
        $first,
        $last,
        $emailNorm,
        $ciudadId,
        $telNorm
    );
    $stmt->execute();
    $newId = $stmt->insert_id;
    $stmt->close();

    return $newId;
}


function getOrCreateUsuarioDireccion(
    $db,
    $userId,
    $first,
    $last,
    $razonSocial,
    $direccion,
    $tel,
    $email,
    $ciudadId,
    $ident
) {
    // 1) Normalizar email y teléfono
    $emailNorm = normalizeEmail($email);
    $telNorm   = normalizePhone($tel);

    // 2) Verificar si ya existe por user y dirección
    $stmt = $db->prepare("
        SELECT id
          FROM tb_usuarios_direcciones
         WHERE idUsuario = ? AND direccion = ?
    ");
    $stmt->bind_param('is', $userId, $direccion);
    $stmt->execute();
    $stmt->bind_result($id);
    if ($stmt->fetch()) {
        $stmt->close();
        return $id;
    }
    $stmt->close();

    // 3) Insertar nueva dirección
    $stmt = $db->prepare("
        INSERT INTO tb_usuarios_direcciones
          (nombre, apellido, razonSocial, direccion, telefono, email, idCiudad, idUsuario, identificacion)
        VALUES (?,?,?,?,?,?,?,?,?)
    ");
    $stmt->bind_param(
        'ssssssiss',
        $first,
        $last,
        $razonSocial,
        $direccion,
        $telNorm,
        $emailNorm,
        $ciudadId,
        $userId,
        $ident
    );
    $stmt->execute();
    $newId = $stmt->insert_id;
    $stmt->close();

    return $newId;
}

use GuzzleHttp\Exception\ClientException;

function safeGet(SiigoClient $client, string $uri, array $params, int $maxRetries = 5): array
{
    $attempt = 0;
    do {
        try {
            return $client->get($uri, $params);
        } catch (ClientException $e) {
            $status = $e->getResponse()->getStatusCode();
            if ($status === 429 && $attempt < $maxRetries) {
                // Si la cabecera Retry-After existe, la usamos; si no, dormimos 3s
                $retryAfter = $e->getResponse()->getHeaderLine('Retry-After');
                $wait = is_numeric($retryAfter) ? (int)$retryAfter : 3;
                echo "Rate limit excedido, espero {$wait}s y reintento (intento #" . ($attempt + 1) . ")...\n";
                sleep($wait);
                $attempt++;
                continue;
            }
            // si no es 429 o superamos maxRetries, relanzamos
            throw $e;
        }
    } while (true);
}

echo "Importación de todos los terceros completada.\n";
