<?php

ini_set('memory_limit', '256M');
ini_set('max_execution_time', '300');

require __DIR__ . '/vendor/autoload.php';

use Dotenv\Dotenv;

date_default_timezone_set('America/Montreal');

$baseDir   = __DIR__;
$tokenFile = $baseDir . "/token_prod.json";
$logFile   = $baseDir . "/logs.json";

// ---------------------------------------------------------
// LOG
// ---------------------------------------------------------
function logMsg($msg)
{
    global $logFile;
    file_put_contents($logFile, date("Y-m-d H:i:s") . " | $msg\n", FILE_APPEND);
}

function fail($msg)
{
    logMsg("ERROR: $msg");
    exit(1);
}

// ---------------------------------------------------------
// CLEAN (no accents)
// ---------------------------------------------------------
function clean($value)
{
    $value = trim($value ?? '');
    $value = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $value);
    return preg_replace('/[^A-Za-z0-9 \-]/', '', $value);
}

// ---------------------------------------------------------
// EXTRACT NUMBER
// ---------------------------------------------------------
function extractNumber($str)
{
    preg_match_all('/\d+/', $str ?? '', $m);
    return array_sum($m[0]);
}

// ---------------------------------------------------------
// BATHROOM TYPE → ARRAY
// ---------------------------------------------------------
function parseBathroomType(string $value): array
{
    $value = trim($value);
    $map = [
        'Bain-douche'                  => ['Bath'],
        'Bain et douche séparés'                 => ['Shower', 'Bath'],
        "Douche"  => ['Shower'],
    ];
    return $map[$value] ?? [];
}

// ---------------------------------------------------------
// AVAILABILITY → STRING
// Priorité :
//   1. Contract_Signed_Conditional__c == true → "Conditional"
//   2. Transfer_Requested__c == true          → "Cession"
//   3. Reserved_Formula__c == true            → "Reserved"
//   4. Available__c == true                 z  → "Available"
//   5. Rented__c == true                      → "Rented"
//   6. Occupied__c == true                    → "Occupied"
// ---------------------------------------------------------
function deriveAvailability(array $rec): string
{
    $isReserved = (
        $rec['Reserved_Formula__c'] === true   ||
        $rec['Reserved_Formula__c'] === 'true' ||
        $rec['Reserved_Formula__c'] === 1
    );

    if ($rec['Contract_Signed_Conditional__c'] ?? false) return 'Conditional';
    if ($rec['Transfer_Requested__c']          ?? false) return 'Cession';
    if ($isReserved)                                     return 'Reserved';
    if ($rec['Available__c']                   ?? false) return 'Available';
    if ($rec['Rented__c']                      ?? false) return 'Rented';
    if ($rec['Occupied__c']                    ?? false) return 'Occupied';
    return '';
}

// ---------------------------------------------------------
// STORAGE SIZE
// ---------------------------------------------------------
function deriveStorageSize(float $surface): string
{
    if ($surface <= 0) return '';
    if ($surface < 20) return 'small';
    if ($surface < 40) return 'medium';
    return 'large';
}

// ---------------------------------------------------------
// UNIT SIZE CLASS
// ---------------------------------------------------------
function computeUnitSizeClass(string $rawType): string
{
    $lower = trim(mb_strtolower($rawType));

    if ($lower === '') return '';

    if ($lower === '2' || str_contains($lower, 'studio')) {
        return 'Studio';
    }

    $isBureau = str_contains($lower, 'bureau');
    $suffix   = $isBureau ? 'B' : 'A';

    if (preg_match('/([0-9]+)\s*½/', $rawType, $m)) {
        return $m[1] . 'etdemi' . $suffix;
    }

    if (preg_match('/^([0-9]+)/', $lower, $m)) {
        return $m[1] . $suffix;
    }

    return '';
}

// ---------------------------------------------------------
// LOAD ENV
// ---------------------------------------------------------
$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();

$clientId     = $_ENV['SF_CLIENT_ID'];
$clientSecret = $_ENV['SF_CLIENT_SECRET'];
$tokenUrl     = $_ENV['SF_TOKEN_URL'];
$refreshToken = $_ENV['SF_REFRESH_TOKEN'];

// ---------------------------------------------------------
// TOKEN
// ---------------------------------------------------------
function getToken()
{
    global $tokenFile, $clientId, $clientSecret, $refreshToken, $tokenUrl;

    if (file_exists($tokenFile)) {
        $data = json_decode(file_get_contents($tokenFile), true);
        if ($data && time() < ($data['expires_at'] ?? 0)) {
            logMsg("♻️ Token valide");
            return $data;
        }
    }

    logMsg("🔄 Refresh token");

    $payload = [
        "grant_type"    => "refresh_token",
        "client_id"     => $clientId,
        "client_secret" => $clientSecret,
        "refresh_token" => $refreshToken
    ];

    $ch = curl_init($tokenUrl);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => http_build_query($payload),
        CURLOPT_RETURNTRANSFER => true
    ]);

    $res = curl_exec($ch);

    if ($res === false) fail(curl_error($ch));

    $data = json_decode($res, true);

    if (!isset($data["access_token"])) {
        fail("OAuth error: " . $res);
    }

    $tokenData = [
        "access_token" => $data["access_token"],
        "instance_url" => $data["instance_url"],
        "expires_at"   => time() + 7000
    ];

    file_put_contents($tokenFile, json_encode($tokenData, JSON_PRETTY_PRINT));

    return $tokenData;
}

$token       = getToken();
$accessToken = $token["access_token"];
$instanceUrl = $token["instance_url"];

// ---------------------------------------------------------
// SOQL — uniquement les champs utilisés dans les JSON
// ---------------------------------------------------------
$soql = urlencode("
SELECT
Id,
Name,
Price,
Status,
Record_Type_Developer_Name__c,
Unit_Number__c,
Building__c,
Building__r.Name,
Premises_floor__c,
Leasable_Square_Footage__c,
Usable_Square_Footage__c,
Other_Square_footage__c,
Width__c,
Depth__c,
Height__c,
Orientation_of_the_sun__c,
Ambiance__c,
View_of_the_unit__c,
Type_of_unit__c,
Office__c,
Bathroom_equipment__c,
Occupancy_Status__c,
State_of_the_unit__c,
Availability_date__c,
Delivery_date__c,
Contract_Signed_Conditional__c,
Transfer_Requested__c,
Reserved_Formula__c,
Available__c,
Rented__c,
Occupied__c,
Irregular__c,
Corner_unit__c,

Number_of_bathroom_washroom__c,
Type_of_laundry_room__c,
Independent_entrance__c,
Walk_in_entrance__c,
Walk_in_bedrooms__c,
Walk_in_pantry__c,
Locker_in_unit__c,
Parking_Type__c,
Charging_Station__c,
Possibility_Charging_Station__c,
Storage_Type__c
FROM Asset
WHERE Record_Type_Developer_Name__c IN ('Residential_Unit', 'Parking', 'Storage')
");

$url = $instanceUrl . "/services/data/v62.0/query/?q=" . $soql;

logMsg("🌐 URL: " . $instanceUrl . "/services/data/v62.0/query/");

$units          = [];
$parking        = [];
$storage        = [];
$totalProcessed = 0;

// ---------------------------------------------------------
// PAGINATION — traitement page par page (économie mémoire)
// ---------------------------------------------------------
do {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_HTTPHEADER     => ["Authorization: Bearer $accessToken"],
        CURLOPT_RETURNTRANSFER => true
    ]);

    $response = curl_exec($ch);

    if ($response === false) fail(curl_error($ch));

    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    logMsg("📡 HTTP code: " . $httpCode);

    if ($httpCode !== 200) {
        logMsg("📦 Response brute: " . substr($response, 0, 800));
        fail("Salesforce a retourné HTTP $httpCode — voir Response brute ci-dessus");
    }

    $data    = json_decode($response, true);
    $records = $data["records"] ?? [];
    $done    = $data["done"] ?? true;
    $nextUrl = isset($data["nextRecordsUrl"])
        ? $instanceUrl . $data["nextRecordsUrl"]
        : null;

    unset($response, $data);

    // ---------------------------------------------------------
    // MAPPING
    // ---------------------------------------------------------
    foreach ($records as $rec) {

        $recordType   = $rec["Record_Type_Developer_Name__c"] ?? "";
        $nameRaw      = $rec["Unit_Number__c"] ?? $rec["Name"] ?? "";
        $name         = clean(explode('-', $nameRaw)[0]);
        $buildingName = $rec["Building__r"]["Name"] ?? "";
        $subProject   = clean($buildingName);

        $isReserved = (
            $rec['Reserved_Formula__c'] === true   ||
            $rec['Reserved_Formula__c'] === 'true' ||
            $rec['Reserved_Formula__c'] === 1
        );

        // -----------------------------------------------------
        // Residential_Unit
        // -----------------------------------------------------
        if ($recordType === "Residential_Unit") {
            $units[] = [
                "id"         => $rec["Id"],
                "name"       => $name,
                "recordType" => $recordType,
                "subProject" => $subProject,

                "premisesFloor" => clean($rec["Premises_floor__c"] ?? ""),
                "surface"       => (float) ($rec["Leasable_Square_Footage__c"] ?? 0),
                "price"         => [(float) ($rec["Price"] ?? 0), 0],

                "squareFootage" => [
                    "leasable" => (float) ($rec["Leasable_Square_Footage__c"] ?? 0),
                    "usable"   => (float) ($rec["Usable_Square_Footage__c"] ?? 0),
                    "other"    => (float) ($rec["Other_Square_footage__c"] ?? 0),
                ],

                "dimensions" => [
                    "width"  => (float) ($rec["Width__c"] ?? 0),
                    "depth"  => (float) ($rec["Depth__c"] ?? 0),
                    "height" => (float) ($rec["Height__c"] ?? 0),
                ],

                "orientation" => clean($rec["Orientation_of_the_sun__c"] ?? ""),
                "finishing"   => clean($rec["Ambiance__c"] ?? ""),
                "view"        => clean($rec["View_of_the_unit__c"] ?? ""),

                "type"            => clean($rec["Type_of_unit__c"] ?? ""),
                "unitSizeClass"   => computeUnitSizeClass($rec["Type_of_unit__c"] ?? ""),
                "office"          => clean($rec["Office__c"] ?? ""),
                "status"          => clean($rec["Status"] ?? ""),
                "occupancyStatus" => clean($rec["Occupancy_Status__c"] ?? ""),
                "stateOfUnit"     => clean($rec["State_of_the_unit__c"] ?? ""),
                "availability"    => deriveAvailability($rec),

                "availabilityDate" => $rec["Availability_date__c"] ?? "",
                "deliveryDate"     => $rec["Delivery_date__c"] ?? "",

                "isIrregular"         => (bool) ($rec["Irregular__c"] ?? false),
                "isUnitCorner"        => ($rec["Corner_unit__c"] ?? false) ? "true" : "false",
                "isReserved"          => $isReserved,
                "isTransferRequested" => (bool) ($rec["Transfer_Requested__c"] ?? false),

                "bathroomType"     => parseBathroomType($rec["Bathroom_equipment__c"] ?? ""),
                "NbOfBathroom" => extractNumber($rec["Number_of_bathroom_washroom__c"] ?? ""),
                "laundryRoomType"  => clean($rec["Type_of_laundry_room__c"] ?? ""),

                "features" => [
                    "independentEntrance" => (bool) ($rec["Independent_entrance__c"] ?? false),
                    "walkInEntrance"      => (bool) ($rec["Walk_in_entrance__c"] ?? false),
                    "walkInBedrooms"      => (bool) ($rec["Walk_in_bedrooms__c"] ?? false),
                    "walkInPantry"        => clean($rec["Walk_in_pantry__c"] ?? ""),
                    "lockerInUnit"        => (bool) ($rec["Locker_in_unit__c"] ?? false),
                ],
            ];
        }

        // -----------------------------------------------------
        // Parking
        // -----------------------------------------------------
        if ($recordType === "Parking") {
            $parking[] = [
                "id"         => $rec["Id"],
                "name"       => $name,
                "recordType" => $recordType,
                "subProject" => $subProject,

                "availabilityDate" => $rec["Availability_date__c"] ?? "",
                "premisesFloor"    => clean($rec["Premises_floor__c"] ?? ""),
                "surface"          => (float) ($rec["Leasable_Square_Footage__c"] ?? 0),
                "price"            => (int) ($rec["Price"] ?? 0),

                "dimensions" => [
                    "width"  => (float) ($rec["Width__c"] ?? 0),
                    "depth"  => (float) ($rec["Depth__c"] ?? 0),
                    "height" => (float) ($rec["Height__c"] ?? 0),
                ],

                "type"            => clean($rec["Parking_Type__c"] ?? ""),
                "availability"    => deriveAvailability($rec),
                "chargingStation" => (bool) ($rec["Charging_Station__c"] ?? false),

                "isIrregular" => (bool) ($rec["Irregular__c"] ?? false),
                "isReserved"  => $isReserved,

                "features" => [
                    "possibilityChargingStation" => (bool) ($rec["Possibility_Charging_Station__c"] ?? false),
                ],
            ];
        }

        // -----------------------------------------------------
        // Storage
        // -----------------------------------------------------
        if ($recordType === "Storage") {
            $surface = (float) ($rec["Leasable_Square_Footage__c"] ?? 0);

            $storage[] = [
                "id"         => $rec["Id"],
                "name"       => $name,
                "recordType" => $recordType,
                "subProject" => $subProject,

                "availabilityDate" => $rec["Availability_date__c"] ?? "",
                "deliveryDate"     => $rec["Delivery_date__c"] ?? "",
                "premisesFloor"    => clean($rec["Premises_floor__c"] ?? ""),
                "surface"          => $surface,
                "price"            => (int) ($rec["Price"] ?? 0),

                "dimensions" => [
                    "width"  => (float) ($rec["Width__c"] ?? 0),
                    "depth"  => (float) ($rec["Depth__c"] ?? 0),
                    "height" => (float) ($rec["Height__c"] ?? 0),
                ],

                "type"            => clean($rec["Storage_Type__c"] ?? ""),
                "size"            => deriveStorageSize($surface),
                "status"          => clean($rec["Status"] ?? ""),
                "occupancyStatus" => clean($rec["Occupancy_Status__c"] ?? ""),
                "availability"    => deriveAvailability($rec),

                "isIrregular" => (bool) ($rec["Irregular__c"] ?? false),
                "isReserved"  => $isReserved,

                "features" => [
                    "lockerInUnit" => (bool) ($rec["Locker_in_unit__c"] ?? false),
                ],
            ];
        }

        unset($rec);
    }

    $totalProcessed += count($records);
    logMsg("📊 Page traitée : " . count($records) . " enregistrements | Total: " . $totalProcessed);

    unset($records);

    $url = $nextUrl;
} while (!$done && $url);

logMsg("✅ Total traité : " . $totalProcessed . " enregistrements");

// ---------------------------------------------------------
// WRITE JSON — groupé par projet
// ---------------------------------------------------------
function extractProjectName($subProject)
{
    return preg_replace('/-\d+$/', '', $subProject);
}

function writeGroupedJsonFiles($items, $baseDir, $prefix)
{
    $groups = [];

    foreach ($items as $item) {
        $subProject = $item['subProject'] ?? 'unknown';
        $project    = extractProjectName($subProject);
        $groups[$project][] = $item;
    }

    foreach ($groups as $project => $data) {
        $filePath = $baseDir . "/" . $prefix . "-" . $project . ".json";

        file_put_contents(
            $filePath,
            json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
        );

        logMsg("✅ $prefix-$project.json généré (" . count($data) . " items)");
    }
}

writeGroupedJsonFiles($units,   $baseDir, "units");
writeGroupedJsonFiles($parking, $baseDir, "parking");
writeGroupedJsonFiles($storage, $baseDir, "locker");
