<?php

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;



/* Tenant config */
$tenant = ltrim($_POST['tenant'] ?? '', '/'); // TENANT_URL came in like "/eis.enrep.co.uk"
if (file_exists('../../' . $tenant . '/config.php')) {
    require_once('../../' . $tenant  . '/config.php');
}

require '../packages/mailer/Exception.php';
require '../packages/mailer/PHPMailer.php';
require '../packages/mailer/SMTP.php';

$email = $_POST['email'] ?? '';
$type  = $_POST['type']  ?? '';

if (!filter_var($email, FILTER_VALIDATE_EMAIL) || $type === '') {
    echo 'invalid_request';
    exit;
}

/* Check user exists */
if ($type === 'client') {
    $stmt = $con->prepare("SELECT `id` FROM `client_users` WHERE `username` = ? AND `statuslive` = 1 LIMIT 1");
    if (!$stmt) {
        error_log('pwdreset client prepare: ' . $con->error);
        echo 'lookup_error';
        exit;
    }
    $stmt->bind_param('s', $email);
} else {
    $allowed = ['surveyor', 'contractors', 'admins'];
    if (!in_array($type, $allowed, true)) {
        echo 'invalid_type';
        exit;
    }

    $stmt = $con->prepare("SELECT id FROM `$type` WHERE email = ? LIMIT 1");
    if (!$stmt) {
        error_log('pwdreset prepare: ' . $con->error);
        echo 'lookup_error';
        exit;
    }
    $stmt->bind_param('s', $email);
}
$stmt->execute();
$user = $stmt->get_result()->fetch_assoc();
$stmt->close();

if (!$user) {
    echo 'not_found';
    exit;
}

/* Create token */
$token  = bin2hex(random_bytes(32));
$expiry = date('Y-m-d H:i:s', strtotime('+2 hours'));

$ins = $con->prepare("INSERT INTO password_resets (email, token, expires_at, user_type) VALUES (?, ?, ?, ?)");
if (!$ins) {
    error_log('pwdreset insert prepare: ' . $con->error);
    echo 'token_error';
    exit;
}
$ins->bind_param('ssss', $email, $token, $expiry, $type);
if (!$ins->execute()) {
    error_log('pwdreset insert failed: ' . $ins->error);
    echo 'token_error';
    exit;
}
$ins->close();

/* Build reset link */
function encryptResetLinkData(string $data): string
{
    $encryption_key = 'Leekylecallum197!'; // TODO move to config/ENV
    $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
    $encrypted = openssl_encrypt($data, 'aes-256-cbc', $encryption_key, 0, $iv);
    return base64_encode($encrypted . '::' . $iv);
}
$resetData = json_encode(['token' => $token, 'email' => $email, 'type' => $type], JSON_UNESCAPED_SLASHES);
$host = $systemUser ?? ($_SERVER['HTTP_HOST'] ?? 'enrep.co.uk'); // from config
$resetLink = 'https://' . $host . '/reset_password.php?data=' . urlencode(encryptResetLinkData($resetData));

/* Email */
$subject = getCompanyDetails('name') . ' - Password Reset';
$tpl     = file_get_contents(__DIR__ . '/../includes/master/email_template.php');
$message = "Please click the following link to reset your password: <a href=\"{$resetLink}\">RESET</a>";

$body = str_replace(
    ['[MESSAGE]', '[LOGO]', '[ENREP]', '[ADDRESS]', '[CONTACT]', '[SUBJECT]'],
    [
        nl2br($message),
        getCompanyDetails('web') . '/images/company/logo.jpg?' . rand(),
        getCompanyDetails('web') . '/images/logo_border.png?' . rand(),
        getCompanyDetails('address'),
        getCompanyDetails('contact'),
        $subject
    ],
    $tpl
);

function passwordResetGraphPost(string $url, array $headers, $body): array
{
    if (function_exists('curl_init')) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_POST => true,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_POSTFIELDS => $body,
            CURLOPT_TIMEOUT => 60,
        ]);
        $response = curl_exec($ch);
        $status = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);

        if ($response === false) {
            throw new \RuntimeException('Microsoft Graph request failed: ' . $error);
        }

        return ['status' => $status, 'body' => (string)$response];
    }

    $context = stream_context_create([
        'http' => [
            'method' => 'POST',
            'header' => implode("\r\n", $headers),
            'content' => $body,
            'timeout' => 60,
            'ignore_errors' => true,
        ],
    ]);
    $response = file_get_contents($url, false, $context);
    $status = 0;
    if (!empty($http_response_header[0]) && preg_match('/\s(\d{3})\s/', $http_response_header[0], $matches)) {
        $status = (int)$matches[1];
    }

    if ($response === false) {
        throw new \RuntimeException('Microsoft Graph request failed');
    }

    return ['status' => $status, 'body' => (string)$response];
}

function passwordResetGraphAccessToken(string $tenantId, string $clientId, string $clientSecret): string
{
    $result = passwordResetGraphPost(
        'https://login.microsoftonline.com/' . rawurlencode($tenantId) . '/oauth2/v2.0/token',
        ['Content-Type: application/x-www-form-urlencoded'],
        http_build_query([
            'client_id' => $clientId,
            'scope' => 'https://graph.microsoft.com/.default',
            'client_secret' => $clientSecret,
            'grant_type' => 'client_credentials',
        ])
    );
    $data = json_decode($result['body'], true);
    if ($result['status'] < 200 || $result['status'] >= 300 || empty($data['access_token'])) {
        $message = is_array($data) && !empty($data['error_description'])
            ? $data['error_description']
            : $result['body'];
        throw new \RuntimeException('Microsoft 365 token request failed: ' . $message);
    }

    return (string)$data['access_token'];
}

function passwordResetGraphSend(PHPMailer $mail): void
{
    $tenantId = trim((string)getEmailSystemSettings('host'));
    $clientId = trim((string)getEmailSystemSettings('username'));
    $clientSecret = (string)getEmailSystemSettings('password');
    $from = trim((string)getEmailSystemSettings('from'));

    if ($tenantId === '' || $clientId === '' || $clientSecret === '' || $from === '') {
        throw new \RuntimeException('Microsoft 365 mail settings are incomplete');
    }

    if (!$mail->preSend()) {
        throw new \RuntimeException($mail->ErrorInfo ?: 'Unable to prepare email for Microsoft 365');
    }

    $token = passwordResetGraphAccessToken($tenantId, $clientId, $clientSecret);
    $result = passwordResetGraphPost(
        'https://graph.microsoft.com/v1.0/users/' . rawurlencode($from) . '/sendMail',
        [
            'Authorization: Bearer ' . $token,
            'Content-Type: text/plain',
        ],
        base64_encode($mail->getSentMIMEMessage())
    );
    if ($result['status'] < 200 || $result['status'] >= 300) {
        $data = json_decode($result['body'], true);
        $message = is_array($data) && !empty($data['error']['message'])
            ? $data['error']['message']
            : $result['body'];
        throw new \RuntimeException('Microsoft 365 send failed: ' . $message);
    }
}

$mail = new PHPMailer(true);
try {
    $mailType = (int)getEmailSystemSettings('type');
    $mail->SMTPDebug = 0;
    if ($mailType === 1) {
        $mail->isSMTP();
        $mail->Host = getEmailSystemSettings('host');
        $mail->SMTPAuth = true;
        $mail->Username = getEmailSystemSettings('username');
        $mail->Password = getEmailSystemSettings('password');
        $mail->SMTPSecure = 'tls';
        $mail->Port = 587;
    } elseif ($mailType === 0) {
        $mail->isSendmail();
    }
    $mail->CharSet    = 'UTF-8';

    $from = getEmailSystemSettings('from');
    $fromName = getEmailSystemSettings('from_name');

    $mail->setFrom($from, $fromName);
    $mail->addAddress($email);
    $mail->isHTML(true);
    $mail->Subject = $subject;
    $mail->Body    = $body;
    $mail->AltBody = strip_tags($message);

    if ($mailType === 2) {
        passwordResetGraphSend($mail);
    } else {
        $mail->send();
    }
    echo 'success';
} catch (\Throwable $e) {
    error_log('pwdreset mail failed: ' . ($mail->ErrorInfo ?: $e->getMessage()));
    echo 'mail_error';
}
