<?php
/**
 * Contracts Admin MVP
 * Single-file admin + JSON API for listing, editing, and emailing contract links.
 */

declare(strict_types=1);
date_default_timezone_set('Australia/Hobart');

session_start();
if ($_SERVER["REQUEST_METHOD"] === "POST") {
    // allow the public "mark_signed" webhook to skip CSRF (it uses a shared secret)
    $isMarkSigned = (($_POST['action'] ?? '') === 'mark_signed');
    if (!$isMarkSigned) {
        $ok = isset($_POST["csrf"], $_SESSION["csrf"]) && hash_equals($_SESSION["csrf"], $_POST["csrf"]);
        if (!$ok) {
            http_response_code(403);
            exit("Invalid CSRF token");
        }
    }
}
if (empty($_SESSION["csrf"])) {
    $_SESSION["csrf"] = bin2hex(random_bytes(32));
}
$csrf = htmlspecialchars($_SESSION["csrf"] ?? "", ENT_QUOTES, "UTF-8");

// Load cfg array
$cfg = @include __DIR__ . "/../config.php";
$cfg = is_array($cfg) ? $cfg : [];

// PHPMailer (your internal includes)
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
require_once "../../internal/phpmailer/src/Exception.php";
require_once "../../internal/phpmailer/src/PHPMailer.php";
require_once "../../internal/phpmailer/src/SMTP.php";

define('BASE_URL', rtrim(getenv('APP_BASE_URL') ?: 'https://modulosdesign.com.au', '/') . '/contracts');

/* -------------------------------------------------------------------------- */
/*                                CONFIGURATION                                */
/* -------------------------------------------------------------------------- */

/**
 * If you already have a config.php with DB and SMTP, include it here.
 * You can also define constants below to override.
 */
$external_config = '../config.php';
if (file_exists($external_config)) {
    require_once $external_config;
}

// Contracts directory. Update to your absolute path in production.
if (!defined('CONTRACTS_DIR')) {
    define('CONTRACTS_DIR', '../contracts');
}

// Base URL where the public signing page lives
// Example: https://modulosdesign.com.au/contracts
//if (!defined('BASE_URL')) {
//    define('BASE_URL', 'https://modulosdesign.com.au/contracts/contracts-admin');
//}

// Shared secret so the public signing page can mark a contract as "signed"
if (!defined('ADMIN_SHARED_SECRET')) {
    define('ADMIN_SHARED_SECRET', $cfg['admin_shared_secret'] ?? getenv('CONTRACTS_ADMIN_SHARED_SECRET') ?: '');
}

// Admin auth. Use HTTP Basic Auth for the MVP.
if (!defined('ADMIN_USER')) define('ADMIN_USER', $cfg['admin_user'] ?? getenv('CONTRACTS_ADMIN_USER') ?: 'admin');
if (!defined('ADMIN_PASS')) define('ADMIN_PASS', $cfg['admin_pass'] ?? getenv('CONTRACTS_ADMIN_PASS') ?: '');

// Database configuration. If nothing is defined, we auto-fallback to SQLite.
if (!defined('DB_DSN'))  define('DB_DSN', 'sqlite:' . __DIR__ . '/contracts.sqlite');
if (!defined('DB_USER')) define('DB_USER', '');
if (!defined('DB_PASS')) define('DB_PASS', '');

// Optional: SMTP configuration if you prefer PHPMailer or similar.
// For the MVP we use mail() by default. If you have PHPMailer autoloaded, we will try to use it.
if (!defined('MAIL_FROM')) define('MAIL_FROM', 'no-reply@modulosdesign.com.au');
if (!defined('MAIL_FROM_NAME')) define('MAIL_FROM_NAME', 'Modulos Design');

// --- LOA (Authorisation) config ---
if (!defined('LOA_DIR'))         define('LOA_DIR', '../loa'); // sibling to ../contracts
if (!defined('LOA_BASE_URL'))    define('LOA_BASE_URL', rtrim(getenv('APP_BASE_URL') ?: 'https://modulosdesign.com.au', '/') . '/contracts');
// IMPORTANT: set this to the SAME secret used in loa.php ($CFG['secret'] / APP_HMAC_SECRET)
if (!defined('LOA_TOKEN_SECRET')) define('LOA_TOKEN_SECRET', $cfg['loa_secret'] ?? getenv('LOA_TOKEN_SECRET') ?: '');


$tab = $_GET['tab'] ?? 'contracts';

/* -------------------------------------------------------------------------- */
/*                               HELPER FUNCTIONS                              */
/* -------------------------------------------------------------------------- */

function require_admin_auth(): void {
    if (!isset($_SERVER['PHP_AUTH_USER'])) {
        header('WWW-Authenticate: Basic realm="Contracts Admin"');
        header('HTTP/1.0 401 Unauthorized');
        echo 'Auth required';
        exit;
    }
    if ($_SERVER['PHP_AUTH_USER'] !== ADMIN_USER || ($_SERVER['PHP_AUTH_PW'] ?? '') !== ADMIN_PASS) {
        header('WWW-Authenticate: Basic realm="Contracts Admin"');
        header('HTTP/1.0 401 Unauthorized');
        echo 'Invalid credentials';
        exit;
    }
}

function json_response(array $payload, int $code = 200): void {
    http_response_code($code);
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    exit;
}

function clientid_from_filename(string $fn): string {
    return preg_replace('/\.md$/i', '', basename($fn));
}

function safe_clientid(string $id): string {
    // Accept digits and simple ids like "3043" or "client-3043". Adjust if needed.
    if (!preg_match('/^[A-Za-z0-9_-]+$/', $id)) {
        throw new RuntimeException('Invalid client id');
    }
    return $id;
}

function contract_path(string $clientid): string {
    $found = find_contract_path_by_clientid($clientid);
    if ($found) return $found; // existing file in any subfolder

    // default location for new files
    $id = safe_clientid($clientid);
    return rtrim(CONTRACTS_DIR, '/\\') . DIRECTORY_SEPARATOR . $id . '.md';
}

function ensure_db(): PDO {
    static $pdo = null;
    if ($pdo instanceof PDO) return $pdo;

    $pdo = new PDO(DB_DSN, DB_USER, DB_PASS, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ]);

    // Create table if missing
    $pdo->exec("CREATE TABLE IF NOT EXISTS contract_status (
        clientid        TEXT PRIMARY KEY,
        sent            INTEGER DEFAULT 0,
        sent_at         TEXT NULL,
        signed          INTEGER DEFAULT 0,
        signed_at       TEXT NULL,
        last_email_to   TEXT NULL,
        pdf_path        TEXT NULL,
        signer_name     TEXT NULL,
        signer_ip       TEXT NULL
    )");

    return $pdo;
}

function get_status(string $clientid): array {
    $pdo = ensure_db();
    $stmt = $pdo->prepare("SELECT * FROM contract_status WHERE clientid = :id");
    $stmt->execute([':id' => $clientid]);
    $row = $stmt->fetch();
    if (!$row) {
        return [
            'clientid' => $clientid,
            'sent' => 0,
            'sent_at' => null,
            'signed' => 0,
            'signed_at' => null,
            'last_email_to' => null,
            'pdf_path' => null,
            'signer_name' => null,
            'signer_ip' => null,
        ];
    }
    return $row;
}

function set_sent(string $clientid, string $email): void {
    $pdo = ensure_db();
    $stmt = $pdo->prepare("INSERT INTO contract_status (clientid, sent, sent_at, last_email_to)
                           VALUES (:id, 1, :now, :email)
                           ON CONFLICT(clientid) DO UPDATE SET
                             sent = 1,
                             sent_at = :now,
                             last_email_to = :email");
    $stmt->execute([
        ':id' => $clientid,
        ':now' => date('Y-m-d H:i:s'),
        ':email' => $email
    ]);
}

function set_signed(string $clientid, ?string $signerName, ?string $signerIp, ?string $pdfPath = null): void {
    $pdo = ensure_db();
    $stmt = $pdo->prepare("INSERT INTO contract_status (clientid, signed, signed_at, signer_name, signer_ip, pdf_path)
                           VALUES (:id, 1, :now, :name, :ip, :pdf)
                           ON CONFLICT(clientid) DO UPDATE SET
                             signed = 1,
                             signed_at = :now,
                             signer_name = COALESCE(:name, signer_name),
                             signer_ip = COALESCE(:ip, signer_ip),
                             pdf_path = COALESCE(:pdf, pdf_path)");
    $stmt->execute([
        ':id' => $clientid,
        ':now' => date('Y-m-d H:i:s'),
        ':name' => $signerName,
        ':ip' => $signerIp,
        ':pdf' => $pdfPath
    ]);
}

function extract_front_matter_fields(string $file): array {
    $out = [];
    $txt = @file_get_contents($file);
    if (!$txt) return $out;

    // Grab the first front matter block
    if (!preg_match('/^---\s*\R(.*?)\R---/s', $txt, $m)) return $out;
    $fm = $m[1];

    // Very simple line-based pulls (keeps dependencies out)
    // client:
    if (preg_match('/^\s*client\s*:\s*$(.*?)^(?=\S)/ms', $fm."\nX", $block)) {
        $clientBlock = $block[1];
        if (preg_match('/^\s*name\s*:\s*["\']?([^"\'\r\n]+)["\']?/mi',  $clientBlock, $mm)) $out['client_name']  = trim($mm[1]);
        if (preg_match('/^\s*email\s*:\s*["\']?([^"\'\r\n]+)["\']?/mi', $clientBlock, $mm)) $out['client_email'] = trim($mm[1]);
        if (preg_match('/^\s*id\s*:\s*["\']?([^"\'\r\n]+)["\']?/mi',    $clientBlock, $mm)) $out['client_id']    = trim($mm[1]);

    }

    if (preg_match('/^\s*project\s*:\s*["\']?([^"\'\r\n]+)["\']?/mi', $fm, $mm)) $out['project'] = trim($mm[1]);
    if (preg_match('/^\s*job\s*:\s*["\']?([^"\'\r\n]+)["\']?/mi',     $fm, $mm)) $out['job']     = trim($mm[1]);

    if (preg_match('/^\s*user\s*:\s*["\']?([^"\'\r\n]+)["\']?/mi',   $fm, $mm)) $out['admin_user']   = trim($mm[1]);
    if (preg_match('/^\s*pass\s*:\s*["\']?([^"\'\r\n]+)["\']?/mi',   $fm, $mm)) $out['admin_pass']   = trim($mm[1]);
    if (preg_match('/^\s*secret\s*:\s*["\']?([^"\'\r\n]+)["\']?/mi', $fm, $mm)) $out['admin_secret'] = trim($mm[1]);

    return $out;
}

function url_join(string $base, string $path): string {
    return rtrim($base, '/') . '/' . ltrim($path, '/');
}

function contract_public_url(string $clientid): string {
    $meta = extract_front_matter_fields(contract_path($clientid));
    $secret = $meta['admin_secret'] ?? ($meta['admin']['secret'] ?? '');
    if ($secret === '') {
        throw new RuntimeException("Missing admin secret for client ID: {$clientid}");
    }
    $token = hash_hmac('sha256', $clientid, $secret);
    $signUrl = url_join(BASE_URL, 'contract.php');
    return $signUrl . '?clientid=' . rawurlencode($clientid) . '&token=' . rawurlencode($token);
}

function email_logo_png_cid(PHPMailer $mail, string $dataUrl, string $alt = 'Modulos Design', int $width = 200): string {
    if ($dataUrl === '') return '';
    // Fast check for the PNG data URL prefix
    $prefix = 'data:image/png;base64,';
    if (stripos($dataUrl, $prefix) !== 0) return '';

    $bin = base64_decode(substr($dataUrl, strlen($prefix)), true);
    if ($bin === false) return '';

    // Stable CID so replies and forwards keep the reference
    $cid = 'logo_' . substr(sha1($bin), 0, 12) . '@modulos';
    $mail->addStringEmbeddedImage($bin, $cid, 'logo.png', 'base64', 'image/png');

    return '<img src="cid:' . $cid . '" alt="' . htmlspecialchars($alt, ENT_QUOTES, 'UTF-8') . '" width="' . (int)$width . '" style="display:block;border:0;outline:0;text-decoration:none;height:auto;">';
}

function salutationFromName(string $fullName): string {
    // Normalize whitespace (incl. NBSP) and collapse runs
    $name = str_replace("\xC2\xA0", ' ', $fullName);
    $name = trim(preg_replace('/\s+/u', ' ', $name));
    if ($name === '') return 'there';

    // Strip a single pair of surrounding quotes if present
    if ($name !== '') {
        $q0 = $name[0];
        $q1 = substr($name, -1);
        if (($q0 === '"' && $q1 === '"') || ($q0 === "'" && $q1 === "'")) {
            $name = substr($name, 1, -1);
            $name = trim($name);
        }
    }

    // Strip common trailing suffixes
    $name = preg_replace(
        '/,?\s*(Jr\.?|Sr\.?|II|III|IV|MD|Ph\.?D|Esq\.?|J\.?D\.?|M\.?B\.?A\.?|RN|DDS|DMD)\s*$/iu',
        '',
        $name
    );

    // Remove one or more leading honorifics (with optional dot)
    $honorifics = '(mr|mrs|ms|miss|mx|dr|prof|sir|dame|lord|lady|hon|rev|fr|father|pastor|rabbi|imam|capt|cpt|gen|col|maj|sgt|officer|chief|coach|pres|sen|rep)';
    while (preg_match('/^' . $honorifics . '\.?[\s\x{00A0}]+/iu', $name)) {
        $name = preg_replace('/^' . $honorifics . '\.?[\s\x{00A0}]+/iu', '', $name, 1);
    }

    // First non-initial token
    foreach (preg_split('/[\s\x{00A0}]+/u', $name) as $tok) {
        $t = rtrim($tok, '.');
        if (!preg_match('/^[A-Za-z]\.?$/u', $t)) return $t;
    }
    return 'there';
}


function send_contract_email(string $email, string $clientid): bool {
    global $cfg;
    $mail = new PHPMailer(true);
    // Build the public link and load metadata from the .md file
    $link      = contract_public_url($clientid);

    $mdPath    = contract_path($clientid);
    $meta      = extract_front_matter_fields($mdPath); // name, email, project, job includes client_name, job, admin.secret, etc.
    $clientName = $meta['client_name'] ?? '';
    $firstName   = salutationFromName($clientName);
    $safeFirst   = htmlspecialchars($firstName ?: 'there', ENT_QUOTES, 'UTF-8');
    $safeCompany = htmlspecialchars($cfg['company_name'] ?? (defined('MAIL_FROM_NAME') ? MAIL_FROM_NAME : 'Modulos Design'), ENT_QUOTES, 'UTF-8');
    $safeJob     = htmlspecialchars($meta['job'] ?? $clientid, ENT_QUOTES, 'UTF-8');
    $safeSignature = email_logo_png_cid($mail, $cfg['dev_signature'] ?? '', $safeCompany, 100);


    // Prepared date from file mtime (or today if missing)
    $prepTs        = @filemtime($mdPath) ?: time();
    $preparedPart  = ' (prepared ' . date('j F Y', $prepTs) . ')';

    // Logo HTML: prefer full HTML from cfg; else build simple <img> if a URL is present
    $logoHtml = email_logo_png_cid($mail, $cfg['dark_logo'] ?? '', $safeCompany, 200);

    $safeUrl = htmlspecialchars($link, ENT_QUOTES, 'UTF-8');

    // Exact same visual structure as your contract.php style, but wording for "ready to sign"
    $html = build_admin_email_html_template(
        $logoHtml,
        $safeJob,
        $safeFirst,
        htmlspecialchars($preparedPart, ENT_QUOTES, 'UTF-8'),
        $safeUrl,
        $safeCompany,
        $safeSignature
    );

    $alt  = "Hello {$safeFirst},\n\n"
        . "Your contract{$preparedPart} is ready to view and sign:\n"
        . "{$link}\n\n"
        . "Thanks again.\n"
        . "Kind Regards,\n{$safeCompany}";

    // Send with PHPMailer using your $cfg SMTP (same pattern as contract.php)
    try {

        $mail->CharSet  = 'UTF-8';
        $mail->Encoding = 'base64';

        // SMTP if host present
        $smtpHost = $cfg['smtp_host'] ?? '';
        if ($smtpHost !== '') {
            $mail->isSMTP();
            $mail->SMTPDebug = SMTP::DEBUG_OFF;
            $mail->Host       = $smtpHost;
            $mail->SMTPAuth   = true;
            $mail->Username   = $cfg['smtp_username'] ?? '';
            $mail->Password   = $cfg['smtp_password'] ?? '';
            $secure = strtolower((string)($cfg['smtp_secure'] ?? 'ssl')); // 'ssl' or 'tls'
            if ($secure === 'ssl') {
                $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
                $mail->Port       = (int)($cfg['smtp_port'] ?? 465);
            } else {
                $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
                $mail->Port       = (int)($cfg['smtp_port'] ?? 587);
            }
        }

        $fromAddress = $cfg['smtp_from']      ?? (defined('MAIL_FROM') ? MAIL_FROM : 'no-reply@modulosdesign.com.au');
        $fromName    = $cfg['smtp_from_name'] ?? (defined('MAIL_FROM_NAME') ? MAIL_FROM_NAME : 'Modulos Design');

        $mail->setFrom($fromAddress, $fromName);
        if (!empty($cfg['smtp_reply_to'])) $mail->addReplyTo($cfg['smtp_reply_to']);
        $mail->addAddress($email);

        // Optional BCC list (comma separated)
        if (!empty($cfg['smtp_bcc'])) {
            foreach (explode(',', $cfg['smtp_bcc']) as $bcc) {
                $bcc = trim($bcc);
                if ($bcc !== '') $mail->addBCC($bcc);
            }
        }

        $mail->isHTML(true);
        $mail->Subject = "Your Building Design contract";
        $mail->Body    = $html;
        $mail->AltBody = $alt;
        $mail->addBCC('drafting@modulosdesign.com.au');

        $mail->send();
        return true;
    } catch (Throwable $e) {
        error_log("contracts-admin: PHPMailer failed for {$email}: ".$e->getMessage());
        // Fallback to mail()
        $headers  = "MIME-Version: 1.0\r\n";
        $headers .= "Content-type: text/html; charset=UTF-8\r\n";
        $headers .= "From: ".$safeCompany." <".$fromAddress.">\r\n";
        return mail($email, "Your Building Design contract", $html, $headers);
    }
}

// Return absolute paths to every *.md under CONTRACTS_DIR (recursively)
function list_all_contract_md_files(): array {
    $base = rtrim(CONTRACTS_DIR, '/\\');
    $files = [];
    if (!is_dir($base)) return $files;

    $it = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator(
            $base,
            FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS
        ),
        RecursiveIteratorIterator::LEAVES_ONLY
    );

    foreach ($it as $path => $info) {
        if ($info->isFile() && strtolower($info->getExtension()) === 'md') {
            $files[] = $path;
        }
    }
    return $files;
}

// Pretty display path (relative to CONTRACTS_DIR)
function contract_relpath(string $abs): string {
    $base = realpath(CONTRACTS_DIR) ?: CONTRACTS_DIR;
    $absR = realpath($abs) ?: $abs;
    $rel  = ltrim(str_replace('\\','/', substr($absR, strlen($base))), '/');
    return $rel ?: basename($absR);
}

// Find the real path for {clientid}.md anywhere under CONTRACTS_DIR
function find_contract_path_by_clientid(string $clientid): ?string {
    $id = safe_clientid($clientid);
    $needle = $id . '.md';

    // quick root check
    $direct = rtrim(CONTRACTS_DIR, '/\\') . DIRECTORY_SEPARATOR . $needle;
    if (is_file($direct)) return $direct;

    $it = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator(
            rtrim(CONTRACTS_DIR, '/\\'),
            FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS
        ),
        RecursiveIteratorIterator::LEAVES_ONLY
    );
    foreach ($it as $path => $info) {
        if ($info->isFile()
            && strtolower($info->getExtension()) === 'md'
            && strcasecmp($info->getFilename(), $needle) === 0) {
            return $path;
        }
    }
    return null;
}


/** Build a starter Markdown file with YAML front matter. */
function build_markdown_template(string $clientid, ?string $name, ?string $email, ?string $project): string {
    $today = date('Y-m-d');
    $name  = $name ?? '';
    $email = $email ?? '';
    $project = $project ?? '';

    // Generate secure random credentials
    $adminUser   = bin2hex(random_bytes(4));   // 8 hex chars (~4 bytes)
    $adminPass   = bin2hex(random_bytes(8));   // 16 hex chars (~8 bytes)
    $adminSecret = bin2hex(random_bytes(16));  // 32 hex chars (~16 bytes)

    $frontMatter = <<<YAML
---
client:
  id: "{$clientid}"
  name: "{$name}"
  email: "{$email}"
  phone:
  address:
project: "{$project}"
dates:
  prepared: "{$today}"
dev:
  name: 'Modulos Design'
  email: 'ben@modulos.com.au'
  phone: '0402 984 082'
  address: '34 Coplestone Street, Scottsdale, Tas 7260'
version: 1
quote:
  number: "{$clientid}"
admin:
  user: "{$adminUser}"
  pass: "{$adminPass}"
  secret: "{$adminSecret}"
---

YAML;

    $body = <<<YAML
    # Contract of work
    This Contract is made and entered into as of the date above by and between **[dev.name]** and **[client.name]** (hereinafter referred to as \"Client\").
    ##### 1. Scope of Services
    YAML;

    return $frontMatter . $body;
}

/* ------------------------- LOA HELPERS ------------------------- */
function loa_path(string $job): string {
    $id = safe_clientid($job);
    return rtrim(LOA_DIR, '/\\') . DIRECTORY_SEPARATOR . $id . '.md';
}
function loa_public_url(string $job): string {
    if (LOA_TOKEN_SECRET === '') {
        error_log('LOA_TOKEN_SECRET is not configured — cannot generate LOA URL');
        return '#loa-token-not-configured';
    }
    $token  = hash_hmac('sha256', 'loa|'.$job, LOA_TOKEN_SECRET);
    $signUrl= url_join(LOA_BASE_URL, 'loa.php');
    return $signUrl . '?job=' . rawurlencode($job) . '&token=' . rawurlencode($token);
}
/** Minimal front-matter pulls for LOA */
function extract_loa_fields(string $file): array {
    $out = ['client_name'=>'','client_email'=>'','client_address'=>'','property_address'=>''];
    $txt = @file_get_contents($file);
    if (!$txt) return $out;
    if (!preg_match('/^---\s*\R(.*?)\R---/s', $txt, $m)) return $out;
    $fm = $m[1];

    $ctx = null;
    foreach (preg_split('/\R/', $fm) as $line) {
        // Any new TOP-LEVEL key (no leading spaces) resets context
        if (preg_match('/^\S[^:]*:\s*$/', $line)) {
            if (preg_match('/^client\s*:\s*$/', $line))   { $ctx = 'client'; }
            elseif (preg_match('/^property\s*:\s*$/', $line)) { $ctx = 'property'; }
            else { $ctx = null; }
            continue;
        }

        if ($ctx === 'client') {
            if (preg_match('/^\s*name\s*:\s*(.+)$/', $line, $mm))   $out['client_name']    = trim($mm[1], " \t\"'");
            if (preg_match('/^\s*email\s*:\s*(.+)$/', $line, $mm))  $out['client_email']   = trim($mm[1], " \t\"'");
            if (preg_match('/^\s*address\s*:\s*(.+)$/', $line, $mm))$out['client_address'] = trim($mm[1], " \t\"'");
        } elseif ($ctx === 'property') {
            if (preg_match('/^\s*address\s*:\s*(.+)$/', $line, $mm))$out['property_address']= trim($mm[1], " \t\"'");
        }
    }

    // Fallback: if no property address, use client address
    if ($out['property_address'] === '' && $out['client_address'] !== '') {
        $out['property_address'] = $out['client_address'];
    }
    return $out;
}


function lookup_job_for_loa(string $job): array {
    $job = safe_clientid($job);
    $empty = ['client_name'=>'','client_email'=>'','property_address'=>'','source'=>null];

    foreach (list_all_contract_md_files() as $file) {
        $txt = @file_get_contents($file); if (!$txt) continue;
        if (!preg_match('/^---\s*\R(.*?)\R---/s', $txt, $m)) continue;
        $fm = $m[1];

        $fm_job = null;
        if (preg_match('/^\s*job\s*:\s*["\']?([^"\r\n]+)["\']?/mi', $fm, $mm)) $fm_job = trim($mm[1]);
        $fname_id = clientid_from_filename($file);

        if ($fm_job === $job || $fname_id === $job) {
            $info = extract_front_matter_fields($file);
            $client_name  = $info['client_name']  ?? '';
            $client_email = $info['client_email'] ?? '';

            $client_addr = null;
            if (preg_match('/^\s*client\s*:\s*$(.*?)^(?=\S)/ms', $fm."\nX", $block)
                && preg_match('/^\s*address\s*:\s*(.+)$/mi', $block[1], $ma)) {
                $client_addr = trim($ma[1], " \t\"'");
            }
            $prop_addr = null;
            if (preg_match('/^\s*property\s*:\s*$(.*?)^(?=\S)/ms', $fm."\nX", $pblock)
                && preg_match('/^\s*address\s*:\s*(.+)$/mi', $pblock[1], $mp)) {
                $prop_addr = trim($mp[1], " \t\"'");
            }
            return [
                'client_name'      => $client_name,
                'client_email'     => $client_email,
                'property_address' => $prop_addr ?: $client_addr ?: '',
                'source'           => 'contract',
                'clientid'         => $fname_id,
            ];
        }
    }
    return $empty;
}



/* -------------------------------------------------------------------------- */
/*                                  API MODE                                   */
/* -------------------------------------------------------------------------- */

$action = $_GET['action'] ?? $_POST['action'] ?? null;
if ($action) {
    // For API calls, enforce admin auth except for mark_signed which uses a shared secret.
    if ($action !== 'mark_signed') {
        require_admin_auth();
    }

    try {
        switch ($action) {
            case 'list':
                $files = glob(rtrim(CONTRACTS_DIR, '/\\') . DIRECTORY_SEPARATOR . '*.md');
                $rows = [];
                foreach ($files as $file) {
                    $clientid = clientid_from_filename($file);
                    $stat = get_status($clientid);

                    // build signed public URL (with token)
                    $publicUrl = null;
                    try {
                        $publicUrl = contract_public_url($clientid);
                    } catch (Throwable $e) {
                        $publicUrl = null; // missing secret or bad front matter
                    }

                    $rows[] = [
                        'clientid' => $clientid,
                        'filename' => basename($file),
                        'size' => filesize($file),
                        'mtime' => filemtime($file),
                        'sent' => (int)($stat['sent'] ?? 0),
                        'sent_at' => $stat['sent_at'] ?? null,
                        'signed' => (int)($stat['signed'] ?? 0),
                        'signed_at' => $stat['signed_at'] ?? null,
                        'last_email_to' => $stat['last_email_to'] ?? null,
                        'public_url' => $publicUrl,   // <-- add this
                    ];
                }
                // Sort by most-recent modified first
                usort($rows, fn($a,$b) => ($b['mtime'] <=> $a['mtime']));
                json_response(['ok' => true, 'contracts' => $rows]);
                break;

            case 'read':
                $clientid = safe_clientid($_GET['clientid'] ?? $_POST['clientid'] ?? '');
                $path = contract_path($clientid);
                if (!file_exists($path)) {
                    json_response(['ok' => false, 'error' => 'File not found'], 404);
                }
                $content = file_get_contents($path);
                json_response(['ok' => true, 'content' => $content]);
                break;

            case 'save':
                $clientid = safe_clientid($_POST['clientid'] ?? '');
                $content = $_POST['content'] ?? '';
                $path = contract_path($clientid);
                if (!is_dir(CONTRACTS_DIR)) {
                    @mkdir(CONTRACTS_DIR, 0775, true);
                }
                $ok = file_put_contents($path, $content, LOCK_EX);
                if ($ok === false) {
                    json_response(['ok' => false, 'error' => 'Write failed'], 500);
                }
                json_response(['ok' => true]);
                break;

            case 'send_link':
                $clientid = safe_clientid($_POST['clientid'] ?? '');
                $email = trim($_POST['email'] ?? '');
                if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
                    json_response(['ok' => false, 'error' => 'Invalid email'], 400);
                }
                $ok = send_contract_email($email, $clientid);
                if ($ok) {
                    set_sent($clientid, $email);
                    json_response(['ok' => true]);
                } else {
                    json_response(['ok' => false, 'error' => 'Failed to send email'], 500);
                }
                break;

            case 'mark_signed':
                // This endpoint is meant to be called from the public contracts.php after a successful signature
                $secret = $_GET['secret'] ?? $_POST['secret'] ?? '';
                if (ADMIN_SHARED_SECRET === '' || $secret !== ADMIN_SHARED_SECRET) {
                    json_response(['ok' => false, 'error' => 'Unauthorized'], 401);
                }
                $clientid = safe_clientid($_GET['clientid'] ?? $_POST['clientid'] ?? '');
                $signerName = $_GET['name'] ?? $_POST['name'] ?? null;
                $pdfPath = $_GET['pdf'] ?? $_POST['pdf'] ?? null;
                $ip = $_SERVER['REMOTE_ADDR'] ?? null;
                set_signed($clientid, $signerName, $ip, $pdfPath);
                json_response(['ok' => true]);
                break;

            case 'toggle_signed':
                // Manual override from the admin UI
                $clientid = safe_clientid($_POST['clientid'] ?? '');
                $flag = (int)($_POST['flag'] ?? 0);
                if ($flag) {
                    set_signed($clientid, null, null, null);
                } else {
                    $pdo = ensure_db();
                    $stmt = $pdo->prepare("UPDATE contract_status SET signed = 0, signed_at = NULL WHERE clientid = :id");
                    $stmt->execute([':id' => $clientid]);
                }
                json_response(['ok' => true]);
                break;
            case 'toggle_sent': {
    $clientid = safe_clientid($_POST['clientid'] ?? '');
    $flag = (int)($_POST['flag'] ?? 0);
    $pdo = ensure_db();
    if ($flag) {
        $stmt = $pdo->prepare("UPDATE contract_status SET sent = 1, sent_at = :now WHERE clientid = :id");
        $stmt->execute([':id' => $clientid, ':now' => date('Y-m-d H:i:s')]);
    } else {
        $stmt = $pdo->prepare("UPDATE contract_status SET sent = 0, sent_at = NULL WHERE clientid = :id");
        $stmt->execute([':id' => $clientid]);
    }
    json_response(['ok' => true]);
    break;
}
            case 'create':
                // Create a new {clientid}.md using a starter template
                $clientid  = safe_clientid($_POST['clientid'] ?? '');
                $name      = trim($_POST['name'] ?? '');
                $email     = trim($_POST['email'] ?? '');
                $project   = trim($_POST['project'] ?? '');
                $overwrite = (int)($_POST['overwrite'] ?? 0);

                $path = contract_path($clientid);
                if (file_exists($path) && !$overwrite) {
                    json_response(['ok' => false, 'error' => 'File already exists'], 409);
                }
                if (!is_dir(CONTRACTS_DIR)) {
                    @mkdir(CONTRACTS_DIR, 0775, true);
                }
                $content = build_markdown_template($clientid, $name, $email, $project);
                $ok = file_put_contents($path, $content, LOCK_EX);
                if ($ok === false) {
                    json_response(['ok' => false, 'error' => 'Create failed'], 500);
                }
                // Seed DB row if missing
                $pdo = ensure_db();
                try {
                    $stmt = $pdo->prepare("INSERT OR IGNORE INTO contract_status (clientid, sent, signed) VALUES (:id, 0, 0)");
                    $stmt->execute([':id' => $clientid]);
                } catch (Throwable $e) {}
                json_response(['ok' => true]);
                break;

            case 'loa_list': {
                require_admin_auth();
                $rows = [];
                foreach (glob(rtrim(LOA_DIR,'/\\').'/*.md') as $file) {
                    $base = basename($file);
                    if ($base === 'default-authorisation.md') continue;
                    $job  = clientid_from_filename($file); // filename without .md
                    $st   = @stat($file);
                    $info = extract_loa_fields($file);
                    $signedPdf = rtrim(LOA_DIR,'/\\')."/{$job}_signed_loa.pdf";
                    $rows[] = [
                        'job'      => $job,
                        'filename' => $base,
                        'mtime'    => $st ? ($st['mtime'] ?? time()) : time(),
                        'client'   => $info['client_name'],
                        'email'    => $info['client_email'],
                        'address'  => $info['property_address'],
                        'signed'   => (int)file_exists($signedPdf),
                        'public_url' => loa_public_url($job),
                        'pdf_url'    => url_join(LOA_BASE_URL, "loa/{$job}_signed_loa.pdf"),
                        'html_url'   => url_join(LOA_BASE_URL, "loa/{$job}_signed_loa.html"),
                    ];
                }
                usort($rows, fn($a,$b)=>($b['mtime']<=>$a['mtime']));
                json_response(['ok'=>true,'loas'=>$rows]); }

            case 'loa_read': {
                require_admin_auth();
                $job = safe_clientid($_GET['job'] ?? $_POST['job'] ?? '');
                $path= loa_path($job);
                if (!file_exists($path)) json_response(['ok'=>false,'error'=>'File not found'],404);
                json_response(['ok'=>true,'content'=>file_get_contents($path)]);
            }

            case 'loa_save': {
                require_admin_auth();
                $job = safe_clientid($_POST['job'] ?? '');
                $content = $_POST['content'] ?? '';
                $path= loa_path($job);
                if (!is_dir(LOA_DIR)) @mkdir(LOA_DIR,0775,true);
                $ok = file_put_contents($path,$content,LOCK_EX);
                if ($ok===false) json_response(['ok'=>false,'error'=>'Write failed'],500);
                json_response(['ok'=>true]);
            }

            case 'loa_create': {
                require_admin_auth();
                $job   = safe_clientid($_POST['job'] ?? '');
                $name  = trim($_POST['client_name'] ?? '');
                $email = trim($_POST['client_email'] ?? '');
                $addr  = trim($_POST['property_address'] ?? '');
                $dst   = loa_path($job);
                if (file_exists($dst) && !((int)($_POST['overwrite'] ?? 0))) {
                    json_response(['ok'=>false,'error'=>'File already exists'],409);
                }
                if (!is_dir(LOA_DIR)) @mkdir(LOA_DIR,0775,true);
                $tpl = @file_get_contents(rtrim(LOA_DIR,'/\\').'/default-authorisation.md') ?: "---\njob: {$job}\n---\n# Authorisation";
                // light substitutions
                $tpl = preg_replace('/^---\R(.+?)\R---/s', function($m) use($job,$name,$email,$addr){
                    $yaml = $m[1];
                    $yaml = preg_replace('/\bjob:\s*.*/','job: '.$job,$yaml);
                    if ($name  !== '') $yaml = preg_replace('/(client:\s*\R(?:.*\R)*?)^\s*name:.*$/m', '$1  name: '.$name, $yaml, 1);
                    if ($email !== '') $yaml = preg_replace('/(client:\s*\R(?:.*\R)*?)^\s*email:.*$/m','$1  email: '.$email,$yaml,1);
                    if ($addr  !== '') $yaml = preg_replace('/(property:\s*\R(?:.*\R)*?)^\s*address:.*$/m','$1  address: '.$addr,$yaml,1);
                    return "---\n".$yaml."\n---";
                }, $tpl, 1) ?? $tpl;
                file_put_contents($dst,$tpl);
                json_response(['ok'=>true]);
            }

            case 'loa_send_link': {
                require_admin_auth();
                $job = safe_clientid($_POST['job'] ?? '');
                $to  = trim($_POST['email'] ?? '');
                if (!filter_var($to, FILTER_VALIDATE_EMAIL)) json_response(['ok'=>false,'error'=>'Invalid email'],400);
                $url = loa_public_url($job);
                $addr = extract_loa_fields(loa_path($job))['property_address'] ?: ('Job '.$job);

                $mail = new PHPMailer(true);
                try {
                    // (mirror your SMTP bootstrap)
                    $smtpHost = $cfg['smtp_host'] ?? '';
                    if ($smtpHost) {
                        $mail->isSMTP();
                        $mail->SMTPDebug = SMTP::DEBUG_OFF;
                        $mail->Host      = $smtpHost;
                        $mail->SMTPAuth  = true;
                        $mail->Username  = $cfg['smtp_username'] ?? '';
                        $mail->Password  = $cfg['smtp_password'] ?? '';
                        $secure = strtolower((string)($cfg['smtp_secure'] ?? 'ssl'));
                        if ($secure === 'ssl') { $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; $mail->Port = (int)($cfg['smtp_port'] ?? 465); }
                        else { $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; $mail->Port = (int)($cfg['smtp_port'] ?? 587); }
                    }
                    $fromAddress = $cfg['smtp_from'] ?? (defined('MAIL_FROM') ? MAIL_FROM : 'no-reply@modulosdesign.com.au');
                    $fromName    = $cfg['smtp_from_name'] ?? (defined('MAIL_FROM_NAME') ? MAIL_FROM_NAME : 'Modulos Design');

                    $mail->setFrom($fromAddress, $fromName);
                    if (!empty($cfg['smtp_reply_to'])) $mail->addReplyTo($cfg['smtp_reply_to']);
                    $mail->addAddress($to);
                    if (!empty($cfg['smtp_bcc'])) foreach (explode(',', $cfg['smtp_bcc']) as $bcc) { $bcc=trim($bcc); if ($bcc) $mail->addBCC($bcc); }
                    // Always keep your audit trail BCC
                    $mail->addBCC('drafting@modulosdesign.com.au');

                    $btn = '<a href="'.htmlspecialchars($url,ENT_QUOTES).'" style="display:inline-block;padding:12px 22px;background:#635A4A;color:#fff;text-decoration:none">Open Authorisation</a>';
                    $mail->isHTML(true);
                    $mail->Subject = "Please review & sign your Authorisation - {$addr}";
                    $mail->Body    = "<p>Hi,</p><p>Please review and sign the Authorisation for <strong>".htmlspecialchars($addr,ENT_QUOTES)."</strong>.</p><p>{$btn}</p><p>If the button doesn't work, use this link:<br>".htmlspecialchars($url,ENT_QUOTES)."</p>";
                    $mail->AltBody = "Please review and sign the Authorisation for {$addr}\n{$url}";
                    $mail->send();
                    json_response(['ok'=>true]);
                } catch (Throwable $e) {
                    error_log('loa_send_link: '.$e->getMessage());
                    json_response(['ok'=>false,'error'=>'Failed to send email'],500);
                }
            }

        	case 'loa_lookup': {
    			require_admin_auth();
    			$job = safe_clientid($_GET['job'] ?? $_POST['job'] ?? '');
    			$data = lookup_job_for_loa($job);
    			$found = (bool)($data['client_name'] || $data['client_email'] || $data['property_address']);
    			json_response(['ok' => true, 'found' => $found, 'data' => $data]);
			}


            default:
                json_response(['ok' => false, 'error' => 'Unknown action'], 400);
        }
    } catch (Throwable $e) {
        json_response(['ok' => false, 'error' => $e->getMessage()], 500);
    }
    exit;
}

/* -------------------------------------------------------------------------- */
/*                               EMAIL TEMPLATE                               */
/*  Build the styled HTML email body identical in structure to contract.php,  */
/*  adjusted for "ready to sign" wording.                                     */
/* -------------------------------------------------------------------------- */

function build_admin_email_html_template(string $logoHtml, string $safeJob, string $firstNameSafe, string $preparedPartHtml, string $safeUrl, string $safeCompany, string $safeSignature): string {
    $html = <<<HTML
<!-- Preheader stays hidden at 0px -->
<div style="display:none;max-height:0;overflow:hidden;opacity:0;mso-hide:all;font-size:0;line-height:0;">
  Your contract is ready to view and sign. Lets get started!
</div>

<div style="background:#f6f7fb;padding:24px;font-size:14px;line-height:1.6;">
  <table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="600"
         style="width:600px;max-width:100%;background:#ffffff;border-radius:8px;overflow:hidden;
                font-size:14px;line-height:1.6;font-family:Arial,Helvetica,sans-serif;">
    <tr>
      <td style="font-size:14px;line-height:1.6;padding:20px 24px;background:#D9CCC1;color:#ffffff;">
        <table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size:14px;line-height:1.6;">
          <tr>
            <td style="font-size:14px;line-height:1.6;">$logoHtml</td>
            <td align="right" style="font-weight:700;font-size:14px;line-height:1.6;">Job #$safeJob</td>
          </tr>
        </table>
      </td>
    </tr>

    <tr>
      <td style="padding:28px 24px 8px;line-height:1.6;color:#635A4A;font-size:14px;">
        <div style="font-size:14px;margin-bottom:8px;line-height:1.6;">Hello {$firstNameSafe},</div>
        <div style="font-size:14px;line-height:1.6;">
          Your contract{$preparedPartHtml} is ready to view and sign. Use the link below:
        </div>
      </td>
    </tr>

    <tr>
      <td align="center" style="padding:20px 24px 8px;font-size:14px;line-height:1.6;">
        <!--[if mso]>
        <v:rect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word"
                href="$safeUrl"
                style="height:42px;v-text-anchor:middle;width:240px;"
                stroked="f" fillcolor="#635A4A">
          <w:anchorlock/>
          <center style="color:#ffffff;font-family:Arial,sans-serif;font-size:16px;line-height:1.6;">View Contract</center>
        </v:rect>
        <![endif]-->

        <!--[if !mso]><!-- -->
        <a href="$safeUrl"
           style="background:#635A4A;border-radius:0;display:inline-block;padding:12px 24px;color:#ffffff;
                  text-decoration:none;font-weight:700;font-size:14px;line-height:1.6;mso-hide:all"
           target="_blank" rel="noopener">View Contract</a>
        <!--<![endif]-->
      </td>
    </tr>

    <tr>
      <td style="padding:8px 24px 24px;font-size:14px;line-height:1.6;color:#635A4A;">
        <div style="font-size:14px;line-height:1.6;">
          If the button doesn’t work, copy and paste this link into your browser:<br>
          <span style="word-break:break-all;color:#635A4A;font-size:14px;line-height:1.6;">$safeUrl</span>
        </div>
        <div style="font-size:14px;line-height:1.6;margin-top:18px;">
          Thank you once again. We’re excited to be working with you and look forward to getting started. Once the contract is signed, we will issue an invoice for the initial deposit and begin work as soon as we receive confirmation.<br><br>
          <b>Kind Regards,</b><br><br>$safeSignature<br>Benjamin Harris<br>$safeCompany<br>0402 984 082  |  drafting@modulosdesign.com.au
        </div>
      </td>
    </tr>

    <tr>
      <td style="padding:12px 24px;background:#28261E;color:#D9CCC1;font-size:14px;line-height:1.6;">
        This is an automated message. Please reply to this email if you have any questions.
      </td>
    </tr>
  </table>
</div>
HTML;
    return $html;
}


// No action, render the admin UI
require_admin_auth();
?>
<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Contracts Admin</title>
        <link rel="shortcut icon" href="../../internal/images/blueprint.ico" type="image/x-icon">

        <meta name="robots" content="noindex">
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-LN+7fdVzj6u52u30Kp6M/trliBMCMKTyK833zpbD+pXdCLuTusPj697FH4R/5mcr" crossorigin="anonymous">
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/js/bootstrap.bundle.min.js" integrity="sha384-ndDqU0Gzau9qJ1lfW4pNLlhNTkCfHzAVBReH9diLvGRem5+R9g2FzA8ZGN954O5Q" crossorigin="anonymous"></script>
        <link href="../../internal/css/blueprint.css" rel="stylesheet">
        <link href="../../internal/css/print.css" rel="stylesheet" media="print">
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
        <style>
            body { background: #f7f7f7; }
            .badge-status { font-size: .85rem; }
            .status-sent { background: #e6f4ea; color: #0f5132; }
            .status-signed { background: #e7f1ff; color: #084298; }
            .monosmall { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: .85rem; }
            .pointer { cursor: pointer; }
            .table thead th { position: sticky; top: 0; background: #fff; z-index: 1; }
        </style>
        <script>window.CSRF = "<?php echo $csrf; ?>";</script>
    </head>

    <nav class="navbar navbar-expand-lg sticky-top bg-brown-dark brown-light border-bottom border-body d-print-none" data-bs-theme="dark">
        <div class="container-fluid">
            <span class="navbar-brand brown-light">
                <img src="../../internal/images/blueprint-logo-light.png" alt="Modulos Design" width="30" height="24" class="d-inline-block align-text-top" >
                Modulos Design
            </span>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarContent" aria-controls="navbarContent" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarContent">
                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    <li class="nav-item">
                        <a class="nav-link active" aria-current="page" href="#">Home</a>
                    </li>
                    <li class="nav-item"><a class="nav-link <?= $tab==='contracts'?'active':'' ?>" href="?tab=contracts">Contracts</a></li>
                    <li class="nav-item"><a class="nav-link <?= $tab==='loas'?'active':'' ?>" href="?tab=loas">LOAs</a></li>
                </ul>
            </div>
        </div>
    </nav>

    <body>
        <div class="container py-4">

            <?php if ($tab === 'contracts'): ?>

            <div class="row">
                <div class="col-12 col-md">
                    <h1 class="h3 mb-0">Contracts Admin</h1>
                </div>
                <div class="col-12 col-md-4">
                    <div class="input-group mb-3">
                        <input id="search" type="search" class="form-control rounded-0" placeholder="Search client id or email">
                        <button class="btn btn-sm bg-brown-five brown-three rounded-0" id="refreshBtn">Refresh Page</button>
                        <button class="btn btn-sm bg-brown-three brown-five rounded-0" id="newBtn">Create New</button>
                    </div>
                </div>
            </div>

            <div class="alert alert-info rounded-0">
                Contracts folder: <span class="monosmall"><?php echo htmlspecialchars(CONTRACTS_DIR, ENT_QUOTES, 'UTF-8'); ?></span>.
                Signing page base URL: <span class="monosmall"><?php echo htmlspecialchars(BASE_URL, ENT_QUOTES, 'UTF-8'); ?></span>
            </div>

            <div class="table-responsive">
                <table class="table table-hover align-middle" id="contractsTable">
                    <thead>
                        <tr>
                            <th>Client ID</th>
                            <th>Client</th>
                            <th>Modified</th>
                            <th>Sent</th>
                            <th>Signed</th>
                            <th>Email</th>
                            <th>Actions</th>
                        </tr>
                    </thead>
                    <tbody></tbody>
                </table>
            </div>
        </div>

        <!-- Edit Modal -->
        <div class="modal fade" id="editModal" tabindex="-1" aria-hidden="true">
            <div class="modal-dialog modal-xl modal-dialog-scrollable">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title">Edit Contract <span id="editClientId" class="text-muted"></span></h5>
                        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                    </div>
                    <div class="modal-body">
                        <textarea id="editContent" class="form-control" rows="20" spellcheck="false"></textarea>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-sm bg-brown-five brown-three rounded-0" data-bs-dismiss="modal">Close</button>
                        <button type="button" class="btn btn-sm bg-brown-three brown-five rounded-0" id="saveBtn">Save</button>
                    </div>
                </div>
            </div>
        </div>

        <!-- Send Modal -->
        <div class="modal fade" id="sendModal" tabindex="-1" aria-hidden="true">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title">Email Contract Link</h5>
                        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                    </div>
                    <div class="modal-body">
                        <div class="mb-3">
                            <label class="form-label">Send to email</label>
                            <input id="sendEmail" type="email" class="form-control" placeholder="client@example.com">
                        </div>
                        <div class="alert alert-secondary">
                            The email includes a link to the signing page for this client id.
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-sm bg-brown-five brown-three rounded-0" data-bs-dismiss="modal">Close</button>
                        <button type="button" class="btn btn-sm bg-brown-three brown-five rounded-0" id="confirmSendBtn">Send</button>
                    </div>
                </div>
            </div>
        </div>

        <!-- New Contract Modal -->
        <div class="modal fade" id="newModal" tabindex="-1" aria-hidden="true">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title">Create new contract</h5>
                        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                    </div>
                    <div class="modal-body">
                        <div class="mb-3">
                            <label class="form-label">Client ID (used for filename)</label>
                            <input id="newClientId" type="text" class="form-control" placeholder="3043">
                            <div class="form-text">Allowed letters, numbers, underscore, hyphen</div>
                        </div>
                        <div class="mb-3">
                            <label class="form-label">Client name</label>
                            <input id="newName" type="text" class="form-control" placeholder="Client Name">
                        </div>
                        <div class="mb-3">
                            <label class="form-label">Client email</label>
                            <input id="newEmail" type="email" class="form-control" placeholder="client@example.com">
                        </div>
                        <div class="mb-3">
                            <label class="form-label">Project title</label>
                            <input id="newProject" type="text" class="form-control" placeholder="Project">
                        </div>
                        <div class="form-check">
                            <input class="form-check-input" type="checkbox" id="newOverwrite">
                            <label class="form-check-label" for="newOverwrite">Overwrite if file exists</label>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-sm bg-brown-five brown-three rounded-0" data-bs-dismiss="modal">Close</button>
                        <button type="button" class="btn btn-sm bg-brown-three brown-five rounded-0" id="createBtn">Create</button>
                    </div>
                </div>
            </div>
        </div>

        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
        <script>
            const tableBody = document.querySelector('#contractsTable tbody');
            const searchInput = document.querySelector('#search');
            const refreshBtn = document.querySelector('#refreshBtn');
            const newBtn = document.querySelector('#newBtn');

            let currentRows = [];
            let currentEditId = null;
            let currentSendId = null;

            function fmtDate(ts) {
                if (!ts) return '';
                const d = new Date(ts * 1000);
                return d.toLocaleString();
            }

            function linkFor(id) {
                return '../contract.php?clientid=' + encodeURIComponent(id);
            }

            function renderTable(rows) {
                tableBody.innerHTML = '';
                rows.forEach(r => {
                    const url = r.public_url || ''; // empty string if missing
                    const tr = document.createElement('tr');
                    tr.innerHTML = `
						<td class="monosmall">${r.clientid}</td>
						<td>${r.filename}</td>
						<td>${fmtDate(r.mtime)}</td>
						<td>
						${r.sent ? '<span class="badge badge-status status-sent">✓ sent</span>' : '<span class="text-muted">—</span>'}
						<button class="btn rounded-0 btn-sm ${r.sent ? 'btn-outline-danger' : 'btn-outline-success'} ms-2 toggleSentBtn">${r.sent ? 'Clear' : 'Mark sent'}</button>
									</td>
						<td>
						${r.signed ? '<span class="badge badge-status status-signed">✓ signed</span>' : '<span class="text-muted">—</span>'}
						<button class="btn rounded-0 btn-sm ${r.signed ? 'btn-outline-danger' : 'btn-outline-success'} ms-2 toggleSignedBtn">${r.signed ? 'Clear' : 'Mark signed'}</button>
									</td>
						<td>${r.last_email_to ? r.last_email_to : ''}</td>
						<td>
						<div class="btn-group">
						<button class="btn rounded-0 btn-sm bg-brown-five brown-three editBtn">Edit</button>
						<button class="btn rounded-0 btn-sm bg-brown-three brown-five sendBtn">Email link</button>
						<button class="btn rounded-0 btn-sm btn-outline-dark copyBtn" data-link="${url}">Copy link</button>
						<a class="btn rounded-0 btn-sm btn-outline-secondary" href="${url}" target="_blank" rel="noopener">Open</a>
						</div>
						</td>`;
                    tr.querySelector('.editBtn').addEventListener('click', () => openEdit(r.clientid));
                    tr.querySelector('.sendBtn').addEventListener('click', () => openSend(r.clientid));
                    tr.querySelector('.copyBtn').addEventListener('click', (ev) => {
  						const url = ev.currentTarget.getAttribute('data-link') || '';
  						if (url) navigator.clipboard.writeText(url);
					});
                    tr.querySelector('.toggleSignedBtn').addEventListener('click', async () => {
                        const flag = r.signed ? 0 : 1;
                        const fd = new FormData();
                        fd.append('action', 'toggle_signed');
                        fd.append('clientid', r.clientid);
                        fd.append('flag', flag);
                        fd.append('csrf', window.CSRF);
                        const res = await fetch('?action=toggle_signed', { method: 'POST', body: fd });
                        const js = await res.json();
                        if (js.ok) {
                            loadData();
                        } else {
                            alert(js.error || 'Failed');
                        }
                    });
                    tr.querySelector('.toggleSentBtn').addEventListener('click', async () => {
                        const flag = r.sent ? 0 : 1;
                        const fd = new FormData();
                        fd.append('action', 'toggle_sent');
                        fd.append('clientid', r.clientid);
                        fd.append('flag', flag);
                        fd.append('csrf', window.CSRF);
                        const res = await fetch('?action=toggle_sent', { method: 'POST', body: fd });
                        const js = await res.json();
                        if (js.ok) {
                            loadData();
                        } else {
                            alert(js.error || 'Failed');
                        }
                    });
                    tableBody.appendChild(tr);
                });
            }

            async function loadData() {
                const res = await fetch('?action=list');
                const js = await res.json();
                if (!js.ok) {
                    alert(js.error || 'Failed to load');
                    return;
                }
                currentRows = js.contracts;
                applyFilter();
            }

            function applyFilter() {
                const q = searchInput.value.trim().toLowerCase();
                if (!q) {
                    renderTable(currentRows);
                    return;
                }
                const rows = currentRows.filter(r =>
                                                r.clientid.toLowerCase().includes(q) ||
                                                (r.last_email_to || '').toLowerCase().includes(q)
                                               );
                renderTable(rows);
            }

            async function openEdit(id) {
                currentEditId = id;
                const res = await fetch('?action=read&clientid=' + encodeURIComponent(id));
                const js = await res.json();
                if (!js.ok) { alert(js.error || 'Failed'); return; }
                document.querySelector('#editClientId').textContent = id;
                document.querySelector('#editContent').value = js.content;
                const modal = new bootstrap.Modal('#editModal');
                modal.show();
            }

            document.querySelector('#saveBtn').addEventListener('click', async () => {
                const content = document.querySelector('#editContent').value;
                const fd = new FormData();
                fd.append('action', 'save');
                fd.append('clientid', currentEditId);
                fd.append('content', content);
                fd.append('csrf', window.CSRF);
                const res = await fetch('?action=save', { method: 'POST', body: fd });
                const js = await res.json();
                if (js.ok) {
                    bootstrap.Modal.getInstance(document.querySelector('#editModal')).hide();
                    loadData();
                } else {
                    alert(js.error || 'Save failed');
                }
            });

            function openSend(id) {
                currentSendId = id;
                document.querySelector('#sendEmail').value = '';
                const modal = new bootstrap.Modal('#sendModal');
                modal.show();
            }

            document.querySelector('#confirmSendBtn').addEventListener('click', async () => {
                const email = document.querySelector('#sendEmail').value.trim();
                if (!email) { alert('Please enter an email'); return; }
                const fd = new FormData();
                fd.append('action', 'send_link');
                fd.append('clientid', currentSendId);
                fd.append('email', email);
                fd.append('csrf', window.CSRF);
                const res = await fetch('?action=send_link', { method: 'POST', body: fd });
                const js = await res.json();
                if (js.ok) {
                    bootstrap.Modal.getInstance(document.querySelector('#sendModal')).hide();
                    loadData();
                } else {
                    alert(js.error || 'Failed to send');
                }
            });

            newBtn.addEventListener('click', () => {
                document.querySelector('#newClientId').value = '';
                document.querySelector('#newName').value = '';
                document.querySelector('#newEmail').value = '';
                document.querySelector('#newProject').value = '';
                document.querySelector('#newOverwrite').checked = false;
                const modal = new bootstrap.Modal('#newModal');
                modal.show();
            });

            document.querySelector('#createBtn').addEventListener('click', async () => {
                const id = document.querySelector('#newClientId').value.trim();
                const name = document.querySelector('#newName').value.trim();
                const email = document.querySelector('#newEmail').value.trim();
                const project = document.querySelector('#newProject').value.trim();
                const overwrite = document.querySelector('#newOverwrite').checked ? 1 : 0;
                if (!id) { alert('Client ID is required'); return; }
                const fd = new FormData();
                fd.append('action', 'create');
                fd.append('clientid', id);
                fd.append('name', name);
                fd.append('email', email);
                fd.append('project', project);
                fd.append('overwrite', overwrite);
                fd.append('csrf', window.CSRF);
                const res = await fetch('?action=create', { method: 'POST', body: fd });
                const js = await res.json();
                if (js.ok) {
                    bootstrap.Modal.getInstance(document.querySelector('#newModal')).hide();
                    loadData();
                } else {
                    alert(js.error || 'Create failed');
                }
            });

            searchInput.addEventListener('input', applyFilter);
            refreshBtn.addEventListener('click', loadData);

            loadData();
        </script>

        <?php else: /* LOAs tab */ ?>
        <div class="row">
            <div class="col-12 col-md">
                <h1 class="h3 mb-0">LOA Admin</h1>
            </div>
            <div class="col-12 col-md-4">
                <div class="input-group mb-3">
                    <input id="loaSearch" type="search" class="form-control rounded-0" placeholder="Search job, client, email">
                    <button class="btn btn-sm bg-brown-five brown-three rounded-0" id="loaRefreshBtn">Refresh Page</button>
                    <button class="btn btn-sm bg-brown-three brown-five rounded-0" id="loaNewBtn">Create LOA</button>
                </div>
            </div>
        </div>

        <div class="alert alert-info rounded-0">
            LOA folder: <span class="monosmall"><?= htmlspecialchars(LOA_DIR, ENT_QUOTES) ?></span>.
            Signing page base URL: <span class="monosmall"><?= htmlspecialchars(LOA_BASE_URL, ENT_QUOTES) ?>/loa.php</span>
        </div>

        <div class="table-responsive">
            <table class="table table-hover align-middle" id="loaTable">
                <thead>
                    <tr>
                        <th>Job</th>
                        <th>Client</th>
                        <th>Property</th>
                        <th>Modified</th>
                        <th>Signed</th>
                        <th>Email</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody></tbody>
            </table>
        </div>

        <!-- LOA Edit Modal -->
        <div class="modal fade" id="loaEditModal" tabindex="-1" aria-hidden="true">
            <div class="modal-dialog modal-xl modal-dialog-scrollable">
                <div class="modal-content">
                    <div class="modal-header"><h5 class="modal-title">Edit LOA <span id="loaEditJob" class="text-muted"></span></h5>
                        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button></div>
                    <div class="modal-body">
                        <textarea id="loaEditContent" class="form-control" rows="20" spellcheck="false"></textarea>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-sm bg-brown-five brown-three rounded-0" data-bs-dismiss="modal">Close</button>
                        <button type="button" class="btn btn-sm bg-brown-three brown-five rounded-0" id="loaSaveBtn">Save</button>
                    </div>
                </div>
            </div>
        </div>

        <!-- LOA Send Modal -->
        <div class="modal fade" id="loaSendModal" tabindex="-1" aria-hidden="true">
            <div class="modal-dialog"><div class="modal-content">
                <div class="modal-header"><h5 class="modal-title">Email LOA Link</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button></div>
                <div class="modal-body">
                    <div class="mb-3"><label class="form-label">Send to email</label>
                        <input id="loaSendEmail" type="email" class="form-control" placeholder="client@example.com"></div>
                    <div class="alert alert-secondary">The email includes a link to the LOA signing page for this job.</div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-sm bg-brown-five brown-three rounded-0" data-bs-dismiss="modal">Close</button>
                    <button type="button" class="btn btn-sm bg-brown-three brown-five rounded-0" id="loaConfirmSendBtn">Send</button>
                </div>
                </div></div>
        </div>

        <!-- LOA New Modal -->
        <div class="modal fade" id="loaNewModal" tabindex="-1" aria-hidden="true">
            <div class="modal-dialog"><div class="modal-content">
                <div class="modal-header"><h5 class="modal-title">Create new LOA</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button></div>
                <div class="modal-body">
                    <div class="mb-3"><label class="form-label">Job #</label>
                        <input id="loaNewJob" type="text" class="form-control" placeholder="1234"></div>
                    <div class="mb-3"><label class="form-label">Client name</label>
                        <input id="loaNewName" type="text" class="form-control" placeholder="Client Name"></div>
                    <div class="mb-3"><label class="form-label">Client email</label>
                        <input id="loaNewEmail" type="email" class="form-control" placeholder="client@example.com"></div>
                    <div class="mb-3"><label class="form-label">Property address</label>
                        <input id="loaNewAddress" type="text" class="form-control" placeholder="1 Example St, Scottsdale TAS"></div>
                    <div class="form-check">
                        <input class="form-check-input" type="checkbox" id="loaNewOverwrite">
                        <label class="form-check-label" for="loaNewOverwrite">Overwrite if file exists</label>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-sm bg-brown-five brown-three rounded-0" data-bs-dismiss="modal">Close</button>
                    <button type="button" class="btn btn-sm bg-brown-three brown-five rounded-0" id="loaCreateBtn">Create</button>
                </div>
                </div></div>
        </div>

        <script>
            (() => {
                const tbody = document.querySelector('#loaTable tbody');
                const search = document.querySelector('#loaSearch');
                const refresh = document.querySelector('#loaRefreshBtn');
                const btnNew = document.querySelector('#loaNewBtn');

                let rows = [];
                let currentJob = null;

                function fmtDate(ts){ if(!ts) return ''; const d=new Date(ts*1000); return d.toLocaleString(); }

                function render(list){
                    tbody.innerHTML = '';
                    list.forEach(r => {
                        const tr = document.createElement('tr');
                        tr.innerHTML = `
							<td class="monosmall">${r.job}</td>
							<td>${r.client || ''}</td>
							<td>${r.address || ''}</td>
							<td>${fmtDate(r.mtime)}</td>
							<td>${r.signed ? '<span class="badge badge-status status-signed">✓ signed</span>' : '<span class="text-muted">—</span>'}</td>
							<td>${r.email || ''}</td>
							<td>
							<div class="btn-group">
							<button class="btn rounded-0 btn-sm bg-brown-five brown-three loaEditBtn">Edit</button>
							<button class="btn rounded-0 btn-sm bg-brown-three brown-five loaSendBtn">Email link</button>
							<button class="btn rounded-0 btn-sm btn-outline-dark loaCopyBtn">Copy link</button>
							<a class="btn rounded-0 btn-sm btn-outline-secondary" href="${r.public_url}" target="_blank" rel="noopener">Open</a>
							<a class="btn rounded-0 btn-sm btn-outline-success" href="${r.pdf_url}" target="_blank">PDF</a>
							<a class="btn rounded-0 btn-sm btn-outline-success" href="${r.html_url}" target="_blank">HTML</a>
							</div>
							</td>`;
                        tr.querySelector('.loaEditBtn').addEventListener('click', () => openEdit(r.job));
                        tr.querySelector('.loaSendBtn').addEventListener('click', () => openSend(r.job, r.email));
                        tr.querySelector('.loaCopyBtn').addEventListener('click', () => navigator.clipboard.writeText(r.public_url));
                        tbody.appendChild(tr);
                    });
                }

                async function load(){
                    const res = await fetch('?action=loa_list');
                    const js = await res.json();
                    if (!js.ok){ alert(js.error || 'Failed to load'); return; }
                    rows = js.loas;
                    applyFilter();
                }

                function applyFilter(){
                    const q = (search.value||'').toLowerCase().trim();
                    if (!q) return render(rows);
                    const f = rows.filter(r =>
                                          r.job.toLowerCase().includes(q) ||
                                          (r.client||'').toLowerCase().includes(q) ||
                                          (r.email||'').toLowerCase().includes(q) ||
                                          (r.address||'').toLowerCase().includes(q)
                                         );
                    render(f);
                }

                async function openEdit(job){
                    currentJob = job;
                    const res = await fetch('?action=loa_read&job='+encodeURIComponent(job));
                    const js = await res.json();
                    if (!js.ok){ alert(js.error||'Failed'); return; }
                    document.querySelector('#loaEditJob').textContent = job;
                    document.querySelector('#loaEditContent').value = js.content;
                    new bootstrap.Modal('#loaEditModal').show();
                }
                document.querySelector('#loaSaveBtn').addEventListener('click', async () => {
                    const content = document.querySelector('#loaEditContent').value;
                    const fd = new FormData();
                    fd.append('action','loa_save');
                    fd.append('job', currentJob);
                    fd.append('content', content);
                    fd.append('csrf', window.CSRF);
                    const res = await fetch('?action=loa_save', { method:'POST', body: fd });
                    const js = await res.json();
                    if (js.ok) {
                        bootstrap.Modal.getInstance(document.querySelector('#loaEditModal')).hide();
                        load();
                    } else alert(js.error || 'Save failed');
                });

                function openSend(job, prefill){
                    currentJob = job;
                    document.querySelector('#loaSendEmail').value = prefill || '';
                    new bootstrap.Modal('#loaSendModal').show();
                }
                document.querySelector('#loaConfirmSendBtn').addEventListener('click', async () => {
                    const email = document.querySelector('#loaSendEmail').value.trim();
                    if (!email) { alert('Please enter an email'); return; }
                    const fd = new FormData();
                    fd.append('action','loa_send_link');
                    fd.append('job', currentJob);
                    fd.append('email', email);
                    fd.append('csrf', window.CSRF);
                    const res = await fetch('?action=loa_send_link', { method:'POST', body: fd });
                    const js = await res.json();
                    if (js.ok) {
                        bootstrap.Modal.getInstance(document.querySelector('#loaSendModal')).hide();
                        load();
                    } else alert(js.error || 'Failed to send');
                });

                btnNew.addEventListener('click', ()=>{
                    document.querySelector('#loaNewJob').value='';
                    document.querySelector('#loaNewName').value='';
                    document.querySelector('#loaNewEmail').value='';
                    document.querySelector('#loaNewAddress').value='';
                    document.querySelector('#loaNewOverwrite').checked=false;
                    new bootstrap.Modal('#loaNewModal').show();
                });
                document.querySelector('#loaCreateBtn').addEventListener('click', async ()=>{
                    const job = document.querySelector('#loaNewJob').value.trim();
                    if (!job) { alert('Job # is required'); return; }
                    const fd = new FormData();
                    fd.append('action','loa_create');
                    fd.append('job', job);
                    fd.append('client_name', document.querySelector('#loaNewName').value.trim());
                    fd.append('client_email', document.querySelector('#loaNewEmail').value.trim());
                    fd.append('property_address', document.querySelector('#loaNewAddress').value.trim());
                    fd.append('overwrite', document.querySelector('#loaNewOverwrite').checked ? 1 : 0);
                    fd.append('csrf', window.CSRF);
                    const res = await fetch('?action=loa_create', { method:'POST', body: fd });
                    const js = await res.json();
                    if (js.ok) {
                        bootstrap.Modal.getInstance(document.querySelector('#loaNewModal')).hide();
                        load();
                    } else alert(js.error || 'Create failed');
                });

                search.addEventListener('input', applyFilter);
                refresh.addEventListener('click', load);
                load();
            })();
                             
            const jobInput  = document.querySelector('#loaNewJob');
			const nameInput = document.querySelector('#loaNewName');
			const emailInput= document.querySelector('#loaNewEmail');
			const addrInput = document.querySelector('#loaNewAddress');

			function debounce(fn, ms){ let t; return (...args)=>{ clearTimeout(t); t=setTimeout(()=>fn(...args), ms); }; }

			const lookupJob = debounce(async () => {
			  const job = jobInput.value.trim();
			  if (!job) return;
			  try {
				const res = await fetch('?action=loa_lookup&job=' + encodeURIComponent(job));
				const js  = await res.json();
				if (js.ok && js.found && js.data) {
				  const d = js.data;
				  if (d.client_name && !nameInput.value)  nameInput.value  = d.client_name;
				  if (d.client_email && !emailInput.value) emailInput.value = d.client_email;
				  if (d.property_address && !addrInput.value) addrInput.value = d.property_address;

				  // quick visual hint
				  [nameInput, emailInput, addrInput].forEach(el => {
					if (el.value) { el.classList.add('is-valid'); setTimeout(()=>el.classList.remove('is-valid'), 1200); }
				  });
				}
			  } catch(e) { /* ignore */ }
			}, 300);

			jobInput.addEventListener('input', lookupJob);
			jobInput.addEventListener('blur', lookupJob);

        </script>

        <?php endif; ?>

        <footer class="footer fixed-bottom">
            <div class="container">
                <div class="row text-center">
                    <p>© 2025 - Modulos Design</p>
                </div>
            </div>
        </footer>
    </body>
</html>