<?php
declare(strict_types=1);
require_once __DIR__ . '/../../functions/logging.php';

/**
 * EnRep DB-driven automation functions.
 * No shell, no exec, no crontab editing, no CREATE TABLE.
 */

function cronLoadTenantConfigFromRequest(): void {
    if (defined('TENANT_URL')) return;

    $tenant = trim((string)($_REQUEST['tenant'] ?? ''));
    $tenant = ltrim($tenant, '/');

    if ($tenant !== '' && file_exists('../../../' . $tenant . '/config.php')) {
        require_once '../../../' . $tenant . '/config.php';
    }
}

function cronRequireTenantContext(): void {
    cronLoadTenantConfigFromRequest();

    if (!defined('TENANT_URL')) {
        throw new RuntimeException('TENANT_URL is not defined.');
    }
}

function cronServerAccountRoot(): string {
    return dirname(__DIR__, 3);
}

function cronTenantRoot(): string {
    cronRequireTenantContext();

    $tenant = ltrim((string)TENANT_URL, '/');
    $path = cronServerAccountRoot() . '/' . $tenant;

    if (!is_dir($path)) {
        throw new RuntimeException('Tenant root not found: ' . $path);
    }

    return $path;
}

function cronAutomationPath(): string {
    return cronTenantRoot() . '/automation';
}

function cronPublicJobName(string $filename): string {
    $name = pathinfo($filename, PATHINFO_FILENAME);
    $name = str_replace('_', ' ', $name);
    return ucwords(trim($name));
}

function cronIsValidAutomationFile(string $filename): bool {
    $filename = basename($filename);

    if ($filename === '') return false;
    if (!str_ends_with($filename, '.php')) return false;
    if (str_starts_with($filename, '.')) return false;
    if (stripos($filename, 'print') !== false) return false;
    if ($filename === 'run_cron.php') return false;

    return is_file(cronAutomationPath() . '/' . $filename);
}

function cronListAutomationFiles(): array {
    $dir = cronAutomationPath();

    if (!is_dir($dir)) return [];

    $files = scandir($dir);
    if (!$files) return [];

    $out = [];

    foreach ($files as $file) {
        if (!cronIsValidAutomationFile($file)) continue;

        $out[$file] = [
            'filename' => $file,
            'name' => cronPublicJobName($file),
            'path' => $dir . '/' . $file,
        ];
    }

    ksort($out);
    return $out;
}

function cronDbTableExists(mysqli $con): bool {
    $res = $con->query("SHOW TABLES LIKE 'automation_jobs'");
    return $res && $res->num_rows > 0;
}

function cronValidateTime(string $time): bool {
    if (!preg_match('/^\d{2}:\d{2}$/', $time)) return false;

    [$hour, $minute] = explode(':', $time);

    $h = (int)$hour;
    $m = (int)$minute;

    return $h >= 0 && $h <= 23 && $m >= 0 && $m <= 59;
}

function cronNormaliseEmailList(string $raw): array {
    $parts = preg_split('/[\r\n,;]+/', $raw) ?: [];
    $out = [];

    foreach ($parts as $part) {
        $email = trim($part);
        if ($email === '') continue;

        if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $out[] = $email;
        }
    }

    return array_values(array_unique($out));
}

function cronExtractEmailArray(string $content, string $varName): array {
    $pattern = '/\$' . preg_quote($varName, '/') . '\s*=\s*\[(.*?)\]\s*;/s';

    if (!preg_match($pattern, $content, $match)) return [];

    preg_match_all('/[\'"]([^\'"]+@[^\s\'",]+)[\'"]/', $match[1], $matches);

    return array_values(array_unique($matches[1] ?? []));
}

function cronFormatEmailArray(string $varName, array $emails): string {
    $clean = [];

    foreach ($emails as $email) {
        $email = trim((string)$email);
        if ($email === '') continue;
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) continue;

        $clean[] = $email;
    }

    $clean = array_values(array_unique($clean));

    $out = '$' . $varName . " = [\n";

    foreach ($clean as $email) {
        $out .= "    '" . addslashes($email) . "',\n";
    }

    $out .= "];";

    return $out;
}

function cronReplaceEmailArray(string $content, string $varName, array $emails): string {
    $replacement = cronFormatEmailArray($varName, $emails);
    $pattern = '/\$' . preg_quote($varName, '/') . '\s*=\s*\[(.*?)\]\s*;/s';

    if (preg_match($pattern, $content)) {
        return preg_replace($pattern, $replacement, $content, 1) ?? $content;
    }

    return $content . PHP_EOL . PHP_EOL . $replacement . PHP_EOL;
}

function cronReadJobRecipients(string $filename): array {
    $filename = basename($filename);

    if (!cronIsValidAutomationFile($filename)) {
        return ['recipients' => [], 'cc' => [], 'bcc' => []];
    }

    $path = cronAutomationPath() . '/' . $filename;
    $content = file_get_contents($path);

    if (!is_string($content)) {
        return ['recipients' => [], 'cc' => [], 'bcc' => []];
    }

    return [
        'recipients' => cronExtractEmailArray($content, 'recipients'),
        'cc' => cronExtractEmailArray($content, 'cc'),
        'bcc' => cronExtractEmailArray($content, 'bcc'),
    ];
}

function cronUpdateJobRecipients(string $filename, array $recipients, array $cc, array $bcc): bool {
    $filename = basename($filename);

    if (!cronIsValidAutomationFile($filename)) return false;

    $path = cronAutomationPath() . '/' . $filename;
    $content = file_get_contents($path);

    if (!is_string($content)) return false;

    $content = cronReplaceEmailArray($content, 'recipients', $recipients);
    $content = cronReplaceEmailArray($content, 'cc', $cc);
    $content = cronReplaceEmailArray($content, 'bcc', $bcc);

    $ok = file_put_contents($path, $content, LOCK_EX) !== false;
    if ($ok) {
        enrep_log('automation', 'recipients_updated', 'Updated automation job recipients', [
            'entity_type' => 'automation_jobs',
            'entity_id' => $filename,
            'subject' => $filename,
            'recipients' => $recipients,
            'cc' => $cc,
            'bcc' => $bcc,
        ]);
    }

    return $ok;
}

function cronDbGetJobs(mysqli $con): array {
    if (!cronDbTableExists($con)) return [];

    $res = $con->query("SELECT * FROM automation_jobs ORDER BY job_name ASC");
    if (!$res) return [];

    $jobs = [];

    while ($row = $res->fetch_assoc()) {
        $jobs[(string)$row['script']] = $row;
    }

    return $jobs;
}

function cronDbGetJobByScript(mysqli $con, string $script): ?array {
    if (!cronDbTableExists($con)) return null;

    $script = basename($script);

    $stmt = $con->prepare("SELECT * FROM automation_jobs WHERE script = ? LIMIT 1");
    if (!$stmt) return null;

    $stmt->bind_param('s', $script);
    $stmt->execute();

    $res = $stmt->get_result();
    $row = $res->fetch_assoc();

    $stmt->close();

    return $row ?: null;
}

function cronDbSaveJob(
    mysqli $con,
    string $script,
    string $time,
    array $recipients,
    array $cc,
    array $bcc
): bool {
    if (!cronDbTableExists($con)) return false;

    $script = basename($script);

    if (!cronIsValidAutomationFile($script)) return false;
    if (!cronValidateTime($time)) return false;
    if (!cronUpdateJobRecipients($script, $recipients, $cc, $bcc)) return false;

    $existing = cronDbGetJobByScript($con, $script);
    $now = time();
    $jobName = cronPublicJobName($script);

    if ($existing) {
        $stmt = $con->prepare("
            UPDATE automation_jobs
            SET job_name = ?,
                run_time = ?,
                frequency = 'daily',
                status = 1,
                updated_at = ?
            WHERE script = ?
            LIMIT 1
        ");

        if (!$stmt) return false;

        $stmt->bind_param('ssis', $jobName, $time, $now, $script);
        $ok = $stmt->execute();
        $stmt->close();

        if ($ok) {
            enrep_log('automation', 'job_saved', 'Saved automation job', [
                'entity_type' => 'automation_jobs',
                'entity_id' => $script,
                'subject' => $jobName,
                'run_time' => $time,
            ]);
        }

        return $ok;
    }

    $stmt = $con->prepare("
        INSERT INTO automation_jobs
            (job_name, script, frequency, run_time, last_run, status, created_at, updated_at)
        VALUES
            (?, ?, 'daily', ?, 0, 1, ?, ?)
    ");

    if (!$stmt) return false;

    $stmt->bind_param('sssii', $jobName, $script, $time, $now, $now);
    $ok = $stmt->execute();
    $stmt->close();

    if ($ok) {
        enrep_log('automation', 'job_saved', 'Saved automation job', [
            'entity_type' => 'automation_jobs',
            'entity_id' => $script,
            'subject' => $jobName,
            'run_time' => $time,
        ]);
    }

    return $ok;
}

function cronDbToggleJob(mysqli $con, string $script, int $status): bool {
    if (!cronDbTableExists($con)) return false;

    $script = basename($script);
    $status = $status === 1 ? 1 : 0;
    $now = time();

    $stmt = $con->prepare("
        UPDATE automation_jobs
        SET status = ?, updated_at = ?
        WHERE script = ?
        LIMIT 1
    ");

    if (!$stmt) return false;

    $stmt->bind_param('iis', $status, $now, $script);
    $ok = $stmt->execute();
    $stmt->close();

    if ($ok) {
        enrep_log('automation', $status === 1 ? 'job_enabled' : 'job_disabled', ($status === 1 ? 'Enabled' : 'Disabled') . ' automation job', [
            'entity_type' => 'automation_jobs',
            'entity_id' => $script,
            'subject' => $script,
        ]);
    }

    return $ok;
}

function cronDbMarkRun(mysqli $con, int $jobId, int $timestamp): bool {
    $stmt = $con->prepare("
        UPDATE automation_jobs
        SET last_run = ?, updated_at = ?
        WHERE id = ?
        LIMIT 1
    ");

    if (!$stmt) return false;

    $stmt->bind_param('iii', $timestamp, $timestamp, $jobId);
    $ok = $stmt->execute();
    $stmt->close();

    return $ok;
}

function cronBuildJobList(mysqli $con): array {
    $files = cronListAutomationFiles();
    $dbJobs = cronDbGetJobs($con);

    $jobs = [];

    foreach ($files as $filename => $file) {
        $emails = cronReadJobRecipients($filename);
        $db = $dbJobs[$filename] ?? null;

        $jobs[] = [
            'filename' => $filename,
            'name' => $file['name'],
            'path' => $file['path'],
            'db_exists' => $db !== null,
            'active' => $db ? (int)$db['status'] === 1 : false,
            'time' => $db ? substr((string)$db['run_time'], 0, 5) : '',
            'last_run' => $db ? (int)$db['last_run'] : 0,
            'recipients' => $emails['recipients'],
            'cc' => $emails['cc'],
            'bcc' => $emails['bcc'],
        ];
    }

    return $jobs;
}
