<?php
/* ============================================================================
 *  password_reset.php  —  helpers for the forgot/reset-password flow.
 *  require_once '../config/database.php'; require_once '../config/password_reset.php';
 * ==========================================================================*/

if (!function_exists('reset_cfg')) {
    function reset_cfg(): array {
        static $cfg = null;
        if ($cfg === null) $cfg = require __DIR__ . '/reset_config.php';
        return $cfg;
    }
}

if (!function_exists('reset_ensure_table')) {
    function reset_ensure_table(PDO $pdo): void {
        $pdo->exec("
            CREATE TABLE IF NOT EXISTS password_resets (
                id INT AUTO_INCREMENT PRIMARY KEY,
                user_id INT NOT NULL,
                code_hash CHAR(64) NOT NULL,
                channel VARCHAR(16) NOT NULL,
                expires_at DATETIME NOT NULL,
                used_at DATETIME NULL,
                created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
                INDEX idx_user (user_id),
                INDEX idx_hash (code_hash)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
        ");
    }
}

if (!function_exists('reset_find_user')) {
    /* find an active account by email / username / phone / pay_id / customer_code.
       returns ['user_id','name','email','phone'] or null */
    function reset_find_user(PDO $pdo, string $id): ?array {
        $id = trim($id);
        if ($id === '') return null;

        $hasUsername = (bool) $pdo->query("SHOW COLUMNS FROM users LIKE 'username'")->fetch();
        $hasPayId    = (bool) $pdo->query("SHOW COLUMNS FROM customers LIKE 'pay_id'")->fetch();

        $userCond = "u.email = ? OR u.phone = ?";
        $params   = [$id, $id];
        if ($hasUsername) { $userCond .= " OR u.username = ?"; $params[] = $id; }

        $custCond = "c.phone = ? OR c.customer_code = ?";
        $params[] = $id; $params[] = $id;
        if ($hasPayId) { $custCond .= " OR c.pay_id = ?"; $params[] = $id; }

        $sql = "SELECT u.id AS user_id, u.name, u.email AS user_email, u.phone AS user_phone,
                       c.email AS cust_email, c.phone AS cust_phone
                  FROM users u
                  LEFT JOIN customers c ON c.user_id = u.id
                 WHERE ($userCond OR $custCond)
                   AND u.status = 'active'
                 LIMIT 1";
        $st = $pdo->prepare($sql);
        $st->execute($params);
        $row = $st->fetch(PDO::FETCH_ASSOC);
        if (!$row) return null;

        return [
            'user_id' => (int) $row['user_id'],
            'name'    => $row['name'] ?? '',
            'email'   => $row['user_email'] ?: ($row['cust_email'] ?: ''),
            'phone'   => $row['user_phone'] ?: ($row['cust_phone'] ?: ''),
        ];
    }
}

if (!function_exists('reset_create_code')) {
    /* generate a numeric code, store its hash, invalidate older unused codes */
    function reset_create_code(PDO $pdo, int $userId, string $channel): string {
        $cfg = reset_cfg();
        reset_ensure_table($pdo);

        $len = max(4, (int) $cfg['code_length']);
        $lo = 10 ** ($len - 1);
        $hi = (10 ** $len) - 1;
        $code = (string) random_int($lo, $hi);

        /* one active code per user */
        $pdo->prepare("UPDATE password_resets SET used_at = NOW() WHERE user_id = ? AND used_at IS NULL")
            ->execute([$userId]);

        $exp = (new DateTime())->modify('+' . (int) $cfg['code_ttl_minutes'] . ' minutes')->format('Y-m-d H:i:s');
        $pdo->prepare("INSERT INTO password_resets (user_id, code_hash, channel, expires_at) VALUES (?, ?, ?, ?)")
            ->execute([$userId, hash('sha256', $code), $channel, $exp]);

        return $code;
    }
}

if (!function_exists('reset_verify_code')) {
    /* returns true and marks the code used if it is valid for this user */
    function reset_verify_code(PDO $pdo, int $userId, string $code): bool {
        reset_ensure_table($pdo);
        $st = $pdo->prepare("SELECT id FROM password_resets
                              WHERE user_id = ? AND code_hash = ? AND used_at IS NULL AND expires_at > NOW()
                              ORDER BY id DESC LIMIT 1");
        $st->execute([$userId, hash('sha256', trim($code))]);
        $rowId = $st->fetchColumn();
        if (!$rowId) return false;
        $pdo->prepare("UPDATE password_resets SET used_at = NOW() WHERE id = ?")->execute([(int) $rowId]);
        return true;
    }
}

if (!function_exists('reset_normalize_phone')) {
    /* turn a local number into international digits for WhatsApp (no +) */
    function reset_normalize_phone(string $phone, string $countryCode): string {
        $d = preg_replace('/\D+/', '', $phone);
        if ($d === '') return '';
        if (strpos($d, $countryCode) === 0) return $d;          // already has country code
        if ($d[0] === '0') return $countryCode . substr($d, 1); // strip leading 0
        return $countryCode . $d;
    }
}

if (!function_exists('reset_smtp_send')) {
    /* minimal authenticated SMTP client (SSL on 465 / STARTTLS on 587) */
    function reset_smtp_send(array $cfg, string $to, string $subject, string $body): bool {
        $host   = $cfg['smtp_host'];
        $port   = (int) $cfg['smtp_port'];
        $secure = strtolower((string) $cfg['smtp_secure']);
        $user   = $cfg['smtp_user'];
        $pass   = $cfg['smtp_pass'];
        $from   = $cfg['mail_from'];
        $fromNm = $cfg['mail_from_name'];

        $remote = ($secure === 'ssl' ? 'ssl://' : '') . $host . ':' . $port;
        $ctx = stream_context_create(['ssl' => ['verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true]]);
        $fp = @stream_socket_client($remote, $errno, $errstr, 20, STREAM_CLIENT_CONNECT, $ctx);
        if (!$fp) return false;
        stream_set_timeout($fp, 20);

        $read = function () use ($fp) {
            $data = '';
            while (($line = fgets($fp, 515)) !== false) {
                $data .= $line;
                if (strlen($line) >= 4 && $line[3] === ' ') break;
            }
            return $data;
        };
        $cmd = function ($c) use ($fp, $read) { fwrite($fp, $c . "\r\n"); return $read(); };
        $ok  = function ($resp, $codes) {
            foreach ((array) $codes as $c) { if (strpos($resp, (string) $c) === 0) return true; }
            return false;
        };

        $read(); // server greeting
        $ehloHost = $_SERVER['SERVER_NAME'] ?? 'localhost';
        $cmd('EHLO ' . $ehloHost);
        if ($secure === 'tls') {
            $cmd('STARTTLS');
            if (!@stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { fclose($fp); return false; }
            $cmd('EHLO ' . $ehloHost);
        }
        $cmd('AUTH LOGIN');
        $cmd(base64_encode($user));
        $authResp = $cmd(base64_encode($pass));
        if (!$ok($authResp, '235')) { fclose($fp); return false; }

        if (!$ok($cmd('MAIL FROM:<' . $from . '>'), '250')) { fclose($fp); return false; }
        if (!$ok($cmd('RCPT TO:<' . $to . '>'), ['250', '251'])) { fclose($fp); return false; }
        if (!$ok($cmd('DATA'), '354')) { fclose($fp); return false; }

        $subjEnc = '=?UTF-8?B?' . base64_encode($subject) . '?=';
        $headers  = 'Date: ' . date('r') . "\r\n";
        $headers .= 'From: ' . $fromNm . ' <' . $from . ">\r\n";
        $headers .= 'To: <' . $to . ">\r\n";
        $headers .= 'Subject: ' . $subjEnc . "\r\n";
        $headers .= "MIME-Version: 1.0\r\n";
        $headers .= "Content-Type: text/plain; charset=UTF-8\r\n";
        $headers .= "Content-Transfer-Encoding: 8bit\r\n";

        $safeBody = preg_replace('/^\./m', '..', str_replace("\r\n", "\n", $body)); // dot-stuffing
        $safeBody = str_replace("\n", "\r\n", $safeBody);
        fwrite($fp, $headers . "\r\n" . $safeBody . "\r\n.\r\n");
        $final = $read();
        $cmd('QUIT');
        fclose($fp);
        return $ok($final, '250');
    }
}

if (!function_exists('reset_send_email')) {
    function reset_send_email(string $to, string $name, string $code): bool {
        $cfg = reset_cfg();
        if (empty($cfg['email_enabled']) || $to === '') return false;
        $ttl  = (int) $cfg['code_ttl_minutes'];
        $subj = 'Your Seven Digital password reset code';
        $body = "Hello " . ($name !== '' ? $name : '') . ",\n\n"
              . "Your password reset code is: $code\n\n"
              . "It expires in $ttl minutes. If you didn't request this, you can ignore this email.\n\n"
              . "Seven Digital";

        /* prefer authenticated SMTP; fall back to PHP mail() */
        if (!empty($cfg['smtp_enabled']) && !empty($cfg['smtp_host']) && !empty($cfg['smtp_user'])) {
            if (reset_smtp_send($cfg, $to, $subj, $body)) return true;
        }
        $from = $cfg['mail_from_name'] . ' <' . $cfg['mail_from'] . '>';
        $headers = "From: $from\r\nReply-To: " . $cfg['mail_from'] . "\r\nContent-Type: text/plain; charset=UTF-8\r\n";
        return @mail($to, $subj, $body, $headers);
    }
}

if (!function_exists('reset_send_whatsapp')) {
    function reset_send_whatsapp(string $phone, string $code): bool {
        $cfg = reset_cfg();
        if (empty($cfg['whatsapp_enabled']) || $cfg['whatsapp_token'] === '' || $cfg['whatsapp_phone_id'] === '') return false;
        $to = reset_normalize_phone($phone, (string) $cfg['whatsapp_country_code']);
        if ($to === '') return false;

        $url = rtrim($cfg['whatsapp_api_base'], '/') . '/' . $cfg['whatsapp_phone_id'] . '/messages';
        $payload = [
            'messaging_product' => 'whatsapp',
            'to'   => $to,
            'type' => 'template',
            'template' => [
                'name' => $cfg['whatsapp_template'],
                'language' => ['code' => $cfg['whatsapp_lang']],
                'components' => [[
                    'type' => 'body',
                    'parameters' => [['type' => 'text', 'text' => $code]],
                ]],
            ],
        ];
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode($payload),
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $cfg['whatsapp_token'],
                'Content-Type: application/json',
            ],
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 15,
        ]);
        $resp = curl_exec($ch);
        $http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        return $http >= 200 && $http < 300;
    }
}