<?php
declare(strict_types=1);

require_once __DIR__ . '/backup_service.php';

function golder_generate_password(int $length = 14): string
{
    $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#*';
    $out = '';
    for ($i = 0; $i < $length; $i++) {
        $out .= $alphabet[random_int(0, strlen($alphabet) - 1)];
    }
    return $out;
}

function golder_demo_duration_days(): int
{
    return 7;
}

function golder_demo_duration_key(): string
{
    return '7_days';
}

function golder_demo_duration_human(): string
{
    $days = golder_demo_duration_days();
    return ($days === 7) ? '1 Hafta' : ($days . ' Gun');
}

function golder_demo_duration_human_adjective(): string
{
    $days = golder_demo_duration_days();
    return ($days === 7) ? '1 Haftalik' : ($days . ' Gunluk');
}

function golder_demo_expiry_from_now(): string
{
    return gmdate('Y-m-d H:i:s', time() + golder_demo_duration_days() * 86400);
}

function golder_duration_days(string $durationKey): int
{
    $durationKey = strtolower(trim($durationKey));
    if (in_array($durationKey, [golder_demo_duration_key(), 'demo_7_days', '1_week', '2_days', 'demo_2_days'], true)) {
        // Legacy 2-day demo keys are normalized to the new 1-week policy.
        return golder_demo_duration_days();
    }
    // Commercial policy is yearly-only; map legacy keys to yearly.
    return 365;
}

function golder_expiry_from_duration(string $durationKey): string
{
    $days = golder_duration_days($durationKey);
    return gmdate('Y-m-d H:i:s', time() + $days * 86400);
}

function golder_plan_duration_expiry_dates(string $planType, string $durationKey): array
{
    $planType = golder_normalize_plan_type($planType);
    $baseExpiry = golder_expiry_from_duration($durationKey);

    return golder_normalize_plan_expiry_dates(
        $planType,
        golder_plan_requires_desktop_expiry($planType) ? $baseExpiry : '',
        golder_plan_requires_sync_expiry($planType) ? $baseExpiry : ''
    );
}

function golder_resolve_plan_expiry_dates(
    string $planType,
    string $durationKey,
    ?string $desktopExpiryOverride = null,
    ?string $syncExpiryOverride = null
): array {
    $defaults = golder_plan_duration_expiry_dates($planType, $durationKey);
    $desktopCandidate = trim((string)$desktopExpiryOverride) !== ''
        ? (string)$desktopExpiryOverride
        : (string)($defaults['desktop_expiry_date'] ?? '');
    $syncCandidate = trim((string)$syncExpiryOverride) !== ''
        ? (string)$syncExpiryOverride
        : (string)($defaults['sync_expiry_date'] ?? '');

    return golder_normalize_plan_expiry_dates($planType, $desktopCandidate, $syncCandidate);
}

function golder_provision_customer_with_tenant(
    PDO $master,
    string $username,
    string $password,
    string $email,
    string $phone,
    string $planType,
    int $maxPc,
    int $maxWeb,
    string $durationKey,
    bool $isDemo = false,
    int $portalUserId = 0,
    ?string $passwordHashOverride = null,
    int $isAiEnabled = 0,
    ?string $desktopExpiryOverride = null,
    ?string $syncExpiryOverride = null
): array {
    golder_ensure_customers_columns($master);
    golder_ensure_plan_tables($master);

    $username = strtolower(trim($username));
    if ($username === '') {
        $username = 'user_' . substr(bin2hex(random_bytes(4)), 0, 8);
    }

    $existsSt = $master->prepare('SELECT id FROM customers WHERE username = :u LIMIT 1');
    $existsSt->execute([':u' => $username]);
    if ($existsSt->fetch()) {
        $username .= '_' . substr(bin2hex(random_bytes(2)), 0, 4);
    }

    $normalized = golder_normalize_plan_limits($planType, $maxPc, $maxWeb);
    $passwordHash = is_string($passwordHashOverride) ? trim($passwordHashOverride) : '';
    if ($passwordHash === '') {
        $passwordHash = password_hash($password, PASSWORD_DEFAULT);
    }
    if (!is_string($passwordHash) || $passwordHash === '') {
        return ['ok' => false, 'message' => 'Password hash failed.'];
    }

    $suffix = substr(bin2hex(random_bytes(5)), 0, 10);
    $tenantDbName = 'goldr_db_' . $suffix;
    $tenantDbUser = 'usr_' . substr($suffix, 0, 8);
    $tenantDbPass = golder_generate_password(14);

    $resolvedExpiries = golder_resolve_plan_expiry_dates(
        $normalized['plan_type'],
        $durationKey,
        $desktopExpiryOverride,
        $syncExpiryOverride
    );
    $desktopExpiryDate = (string)($resolvedExpiries['desktop_expiry_date'] ?? '');
    $syncExpiryDate = (string)($resolvedExpiries['sync_expiry_date'] ?? '');
    $expiryDate = (string)($resolvedExpiries['expiry_date'] ?? '');
    $demoExpires = $isDemo ? golder_demo_expiry_from_now() : null;
    $dbCreated = false;
    $dbUserCreated = false;

    $master->beginTransaction();
    $customerId = 0;
    try {
        $ins = $master->prepare(
            'INSERT INTO customers
             (username, email, phone_number, portal_user_id, password_hash, plan_type, max_devices, max_pc_devices, max_web_sessions, is_ai_enabled, expiry_date, desktop_expiry_date, sync_expiry_date, mysql_db_name, mysql_db_user, mysql_db_pass, is_demo, demo_expires_at, license_status)
             VALUES
             (:u, :e, :p, :puid, :ph, :pt, :md, :mpc, :mws, :ai, :ex, :dex, :sex, :dbn, :dbu, :dbp, :demo, :demox, :ls)'
        );
        $ins->execute([
            ':u' => $username,
            ':e' => $email,
            ':p' => $phone,
            ':puid' => ($portalUserId > 0 ? $portalUserId : null),
            ':ph' => $passwordHash,
            ':pt' => $normalized['plan_type'],
            ':md' => $normalized['max_pc_devices'],
            ':mpc' => $normalized['max_pc_devices'],
            ':mws' => $normalized['max_web_sessions'],
            ':ai' => $isAiEnabled,
            ':ex' => ($expiryDate !== '' ? $expiryDate : null),
            ':dex' => ($desktopExpiryDate !== '' ? $desktopExpiryDate : null),
            ':sex' => ($syncExpiryDate !== '' ? $syncExpiryDate : null),
            ':dbn' => $tenantDbName,
            ':dbu' => $tenantDbUser,
            ':dbp' => $tenantDbPass,
            ':demo' => $isDemo ? 1 : 0,
            ':demox' => $demoExpires,
            ':ls' => 'active',
        ]);
        $customerId = (int)$master->lastInsertId();
        $master->commit();
    } catch (Throwable $e) {
        if ($master->inTransaction()) {
            $master->rollBack();
        }
        return ['ok' => false, 'message' => 'Customer insert failed: ' . $e->getMessage()];
    }

    try {
        $master->exec(sprintf('CREATE DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci', $tenantDbName));
        $dbCreated = true;
        $master->exec(sprintf("CREATE USER '%s'@'%%' IDENTIFIED BY '%s'", $tenantDbUser, $tenantDbPass));
        $dbUserCreated = true;
        $master->exec(sprintf("GRANT ALL PRIVILEGES ON `%s`.* TO '%s'@'%%'", $tenantDbName, $tenantDbUser));
        $master->exec('FLUSH PRIVILEGES');

        $schemaPath = dirname(__DIR__) . '/goldr.sql';
        if (is_file($schemaPath)) {
            $cfg = golder_master_db_config();
            $cmd = sprintf(
                'mysql -h %s -P %d -u %s -p%s %s < %s 2>&1',
                escapeshellarg((string)$cfg['host']),
                (int)$cfg['port'],
                escapeshellarg((string)$cfg['user']),
                escapeshellarg((string)$cfg['pass']),
                escapeshellarg($tenantDbName),
                escapeshellarg($schemaPath)
            );
            exec($cmd, $out, $ret);
            if ((int)$ret !== 0) {
                throw new RuntimeException('Tenant schema import failed: ' . implode("\n", $out));
            }
        }
    } catch (Throwable $e) {
        try {
            if ($dbCreated) {
                $master->exec(sprintf('DROP DATABASE IF EXISTS `%s`', $tenantDbName));
            }
        } catch (Throwable $_ignored) {
        }
        try {
            if ($dbUserCreated) {
                $master->exec(sprintf("DROP USER IF EXISTS '%s'@'%%'", $tenantDbUser));
                $master->exec('FLUSH PRIVILEGES');
            }
        } catch (Throwable $_ignored) {
        }
        try {
            if ($customerId > 0) {
                $master->prepare('DELETE FROM customers WHERE id = :id')->execute([':id' => $customerId]);
            }
        } catch (Throwable $_ignored) {
        }
        return ['ok' => false, 'message' => 'Tenant provisioning failed: ' . $e->getMessage(), 'customer_id' => $customerId];
    }

    $customer = golder_customer_by_id($master, $customerId);
    if (!$customer) {
        return ['ok' => false, 'message' => 'Provisioned customer could not be loaded.'];
    }

    return [
        'ok' => true,
        'customer_id' => $customerId,
        'username' => $username,
        'password' => $password,
        'customer' => $customer,
    ];
}


