<?php
// /api/towlens/share_upload.php
declare(strict_types=1);

header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Pragma: no-cache');

$ROOT = realpath(__DIR__ . '/../../');
if (!$ROOT) {
    http_response_code(500);
    echo json_encode(['error' => 'Server path resolution failed']);
    exit;
}

$config = require $ROOT . '/lib/config.php';
require $ROOT . '/lib/db.php';

if (!($pdo instanceof PDO)) {
    http_response_code(500);
    echo json_encode(['error' => 'Database unavailable']);
    exit;
}
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$env = $config['env'] ?? 'prod';

function jresp($data, int $status = 200): void {
    http_response_code($status);
    echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

function is_share_token(string $t): bool {
    return (bool)preg_match('/^[a-f0-9]{64}$/', $t);
}
function is_legacy_token(string $t): bool {
    return (bool)preg_match('/^[a-f0-9-]{36}$/i', $t);
}

/** Require POST */
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
if (strtoupper($method) !== 'POST') {
    jresp(['error' => 'Method not allowed'], 405);
}

/** Read token from POST, fall back to GET just in case */
$token    = $_POST['token'] ?? ($_GET['token'] ?? '');
$stepCode = $_POST['step_code'] ?? null;
$tag      = $_POST['tag'] ?? null;

if (!is_share_token($token) && !is_legacy_token($token)) {
    jresp(['error' => 'Invalid token'], 400);
}

/** Ensure events table (idempotent, move to migration later) */
try {
    $pdo->exec("
        CREATE TABLE IF NOT EXISTS towlens_events (
          id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
          request_id INT UNSIGNED DEFAULT NULL,
          share_id INT UNSIGNED DEFAULT NULL,
          file_id INT UNSIGNED DEFAULT NULL,
          event_type VARCHAR(50) NOT NULL,
          details TEXT DEFAULT NULL,
          ip VARCHAR(45) DEFAULT NULL,
          user_agent VARCHAR(255) DEFAULT NULL,
          created_by VARCHAR(190) DEFAULT NULL,
          created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
          INDEX idx_req (request_id),
          INDEX idx_share (share_id),
          INDEX idx_file (file_id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    ");
} catch (Throwable $e) {
    if ($env === 'dev') error_log('TowLens events ensure failed: ' . $e->getMessage());
}

/** Resolve request/share */
$reqId   = null;
$shareId = null;

try {
    if (is_share_token($token)) {
        $stmt = $pdo->prepare("
          SELECT s.id AS share_id,
                 s.expires_at AS share_expires_at,
                 s.status AS share_status,
                 r.id AS request_id
          FROM request_shares s
          JOIN requests r ON r.id = s.request_id
          WHERE s.token = ?
          LIMIT 1
        ");
        $stmt->execute([$token]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$row) jresp(['error' => 'Link invalid'], 400);

        if (!empty($row['share_expires_at']) && $row['share_expires_at'] < date('Y-m-d H:i:s')) {
            $pdo->prepare("UPDATE request_shares SET status='expired' WHERE id=?")
                ->execute([(int)$row['share_id']]);
            jresp(['error' => 'Link expired'], 400);
        }

        $st = strtolower($row['share_status']);
        if (in_array($st, ['expired','cancelled'], true)) {
            jresp(['error' => 'Link closed'], 400);
        }

        $reqId   = (int)$row['request_id'];
        $shareId = (int)$row['share_id'];
    } else {
        $stmt = $pdo->prepare("
          SELECT id, expires_at, status
          FROM requests
          WHERE token = ?
          LIMIT 1
        ");
        $stmt->execute([$token]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$row) jresp(['error' => 'Link invalid'], 400);

        if (!empty($row['expires_at']) && $row['expires_at'] < date('Y-m-d H:i:s')) {
            $pdo->prepare("UPDATE requests SET status='expired' WHERE id=?")
                ->execute([(int)$row['id']]);
            jresp(['error' => 'Link expired'], 400);
        }

        if (strtolower($row['status']) === 'closed') {
            jresp(['error' => 'Request closed'], 400);
        }

        $reqId = (int)$row['id'];
    }
} catch (Throwable $e) {
    if ($env === 'dev') error_log('TowLens token resolution failed: ' . $e->getMessage());
    jresp(['error' => 'Server error resolving link'], 500);
}

/** File validation */
if (empty($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
    jresp(['error' => 'No file uploaded'], 400);
}

$file = $_FILES['file'];
$maxBytes = (int)(($config['max_file_mb'] ?? 15) * 1024 * 1024);

if ($file['size'] <= 0 || $file['size'] > $maxBytes) {
    jresp(['error' => 'Invalid file size'], 400);
}

$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime  = $finfo->file($file['tmp_name']) ?: '';

$allowed = [
    'image/jpeg',
    'image/png',
    'image/heic',
    'image/heif',
    'image/webp',
    'image/gif',
];
if (!in_array($mime, $allowed, true)) {
    jresp(['error' => 'Unsupported file type'], 400);
}

$extMap = [
    'image/jpeg' => '.jpg',
    'image/png'  => '.png',
    'image/heic' => '.heic',
    'image/heif' => '.heif',
    'image/webp' => '.webp',
    'image/gif'  => '.gif',
];
$ext = $extMap[$mime] ?? '.bin';

$storageRoot = $config['towlens_upload_path'] ?? ($ROOT . '/towlens_uploads');
if (!is_dir($storageRoot)) {
    @mkdir($storageRoot, 0775, true);
}

$basename = bin2hex(random_bytes(16)) . $ext;
$target   = $storageRoot . '/' . $basename;

if (!move_uploaded_file($file['tmp_name'], $target)) {
    jresp(['error' => 'Failed to store file'], 500);
}

$hash = hash_file('sha256', $target);
$isBlurry = 0;
$isDark   = 0;
$suspect  = 0;

/** Insert file metadata */
try {
    $ins = $pdo->prepare("
      INSERT INTO request_files
        (request_id, step_code, tag, file_hash,
         is_blurry, is_dark, suspected_damage,
         uploaded_ip, uploaded_user_agent, uploaded_at,
         filename, mime_type, size_bytes)
      VALUES
        (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), ?, ?, ?)
    ");
    $ins->execute([
        $reqId,
        $stepCode,
        $tag,
        $hash,
        $isBlurry,
        $isDark,
        $suspect,
        $_SERVER['REMOTE_ADDR'] ?? null,
        substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 250),
        $basename,
        $mime,
        $file['size'],
    ]);
    $fileId = (int)$pdo->lastInsertId();
} catch (Throwable $e) {
    if ($env === 'dev') error_log('TowLens file insert failed: ' . $e->getMessage());
    jresp(['error' => 'Server error saving metadata'], 500);
}

/** Update share status if applicable */
if ($shareId) {
    try {
        $pdo->prepare("
          UPDATE request_shares
             SET status = IF(status IN ('pending','sent'),'opened',status)
           WHERE id = ?
        ")->execute([$shareId]);
    } catch (Throwable $e) {
        if ($env === 'dev') error_log('TowLens share update failed: ' . $e->getMessage());
    }
}

/** Log event */
try {
    $ev = $pdo->prepare("
      INSERT INTO towlens_events (request_id, share_id, file_id, event_type, ip, user_agent)
      VALUES (?, ?, ?, 'UPLOAD', ?, ?)
    ");
    $ev->execute([
        $reqId,
        $shareId,
        $fileId,
        $_SERVER['REMOTE_ADDR'] ?? null,
        substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 250),
    ]);
} catch (Throwable $e) {
    if ($env === 'dev') error_log('TowLens upload event failed: ' . $e->getMessage());
}

jresp(['status' => 'ok', 'file_id' => $fileId], 201);
