<?php
declare(strict_types=1);

/**
 * EnglishSpeak - Teacher Units
 * File: teacher/units/update.php
 *
 * Updates one Unit while preserving its Lessons and Practices.
 */

require __DIR__ . '/../partials/auth.php';
require_once __DIR__ . '/../../config/database.php';

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    header('Location: index.php');
    exit;
}

$pdo = getDbConnection();

$unitId = max(0, (int)($_POST['id'] ?? 0));
$bookId = max(0, (int)($_POST['book_id'] ?? 0));
$unitNumber = trim((string)($_POST['unit_number'] ?? ''));
$title = trim((string)($_POST['title'] ?? ''));
$description = trim((string)($_POST['description'] ?? ''));
$requiredXp = max(0, (int)($_POST['required_xp'] ?? 0));
$sortOrder = max(0, (int)($_POST['sort_order'] ?? 0));
$status = (string)($_POST['status'] ?? 'active');
$removeThumbnail = (string)($_POST['remove_thumbnail'] ?? '') === '1';

if (!in_array($status, ['active', 'inactive'], true)) {
    $status = 'active';
}

$old = [
    'book_id' => $bookId,
    'unit_number' => $unitNumber,
    'title' => $title,
    'description' => $description,
    'required_xp' => $requiredXp,
    'sort_order' => $sortOrder,
    'status' => $status,
];

$errors = [];

if ($unitId <= 0) {
    $_SESSION['units_message'] = 'Invalid Unit ID.';
    $_SESSION['units_message_type'] = 'error';
    header('Location: index.php');
    exit;
}

// Load current Unit.
$currentStmt = $pdo->prepare(
    "SELECT
        id,
        book_id,
        unit_number,
        title,
        thumbnail,
        description,
        required_xp,
        sort_order,
        status
     FROM units
     WHERE id = ?
     LIMIT 1"
);
$currentStmt->execute([$unitId]);
$currentUnit = $currentStmt->fetch(PDO::FETCH_ASSOC);

if (!$currentUnit) {
    $_SESSION['units_message'] = 'Unit not found.';
    $_SESSION['units_message_type'] = 'error';
    header('Location: index.php');
    exit;
}

// Validate Book.
if ($bookId <= 0) {
    $errors[] = 'Please select a Book.';
} else {
    $bookStmt = $pdo->prepare(
        "SELECT id
         FROM books
         WHERE id = ?
         LIMIT 1"
    );
    $bookStmt->execute([$bookId]);

    if (!$bookStmt->fetchColumn()) {
        $errors[] = 'The selected Book does not exist.';
    }
}

// Validate fields.
if ($unitNumber === '') {
    $errors[] = 'Unit Number is required.';
} elseif (mb_strlen($unitNumber) > 20) {
    $errors[] = 'Unit Number must not exceed 20 characters.';
}

if ($title === '') {
    $errors[] = 'Unit Title is required.';
} elseif (mb_strlen($title) > 150) {
    $errors[] = 'Unit Title must not exceed 150 characters.';
}

if (mb_strlen($description) > 5000) {
    $errors[] = 'Description is too long.';
}

// Unique Unit Number inside one Book, excluding current Unit.
if ($bookId > 0 && $unitNumber !== '') {
    $duplicateStmt = $pdo->prepare(
        "SELECT id
         FROM units
         WHERE book_id = ?
           AND LOWER(TRIM(unit_number)) = LOWER(TRIM(?))
           AND id <> ?
         LIMIT 1"
    );
    $duplicateStmt->execute([$bookId, $unitNumber, $unitId]);

    if ($duplicateStmt->fetchColumn()) {
        $errors[] = 'This Unit Number already exists in the selected Book.';
    }
}

/**
 * Saves a replacement thumbnail.
 *
 * @return string|null Relative project path, or null when no new upload exists.
 */
function updateUnitThumbnail(array &$errors): ?string
{
    if (
        !isset($_FILES['thumbnail'])
        || !is_array($_FILES['thumbnail'])
        || (int)($_FILES['thumbnail']['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE
    ) {
        return null;
    }

    $file = $_FILES['thumbnail'];
    $errorCode = (int)($file['error'] ?? UPLOAD_ERR_NO_FILE);

    if ($errorCode !== UPLOAD_ERR_OK) {
        $errors[] = 'The thumbnail could not be uploaded.';
        return null;
    }

    $tmpPath = (string)($file['tmp_name'] ?? '');
    $size = (int)($file['size'] ?? 0);

    if ($tmpPath === '' || !is_uploaded_file($tmpPath)) {
        $errors[] = 'The uploaded thumbnail is invalid.';
        return null;
    }

    if ($size <= 0 || $size > 3 * 1024 * 1024) {
        $errors[] = 'Thumbnail must be smaller than 3 MB.';
        return null;
    }

    $mime = '';
    if (function_exists('finfo_open')) {
        $finfo = finfo_open(FILEINFO_MIME_TYPE);

        if ($finfo !== false) {
            $mime = (string)finfo_file($finfo, $tmpPath);
            finfo_close($finfo);
        }
    }

    $allowed = [
        'image/jpeg' => 'jpg',
        'image/png' => 'png',
        'image/webp' => 'webp',
    ];

    if (!isset($allowed[$mime])) {
        $errors[] = 'Thumbnail must be a JPG, PNG or WEBP image.';
        return null;
    }

    $projectRoot = dirname(__DIR__, 2);
    $relativeDir = 'uploads/units';
    $absoluteDir = $projectRoot . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'units';

    if (!is_dir($absoluteDir) && !mkdir($absoluteDir, 0775, true) && !is_dir($absoluteDir)) {
        $errors[] = 'The Unit upload folder could not be created.';
        return null;
    }

    try {
        $random = bin2hex(random_bytes(8));
    } catch (Throwable $e) {
        $random = str_replace('.', '', uniqid('', true));
    }

    $filename = 'unit-' . date('Ymd-His') . '-' . $random . '.' . $allowed[$mime];
    $absolutePath = $absoluteDir . DIRECTORY_SEPARATOR . $filename;

    if (!move_uploaded_file($tmpPath, $absolutePath)) {
        $errors[] = 'The thumbnail could not be saved.';
        return null;
    }

    return $relativeDir . '/' . $filename;
}

/**
 * Deletes an existing thumbnail only when it belongs to uploads/units.
 */
function deleteUnitThumbnailFile(?string $relativePath): void
{
    if ($relativePath === null || $relativePath === '') {
        return;
    }

    $normalized = str_replace('\\', '/', ltrim($relativePath, '/'));

    if (!str_starts_with($normalized, 'uploads/units/')) {
        return;
    }

    $absolutePath = dirname(__DIR__, 2)
        . DIRECTORY_SEPARATOR
        . str_replace('/', DIRECTORY_SEPARATOR, $normalized);

    if (is_file($absolutePath)) {
        @unlink($absolutePath);
    }
}

$newThumbnail = null;

if ($errors === []) {
    $newThumbnail = updateUnitThumbnail($errors);
}

if ($errors !== []) {
    $_SESSION['units_old'] = $old;
    $_SESSION['units_errors'] = $errors;
    header('Location: edit.php?id=' . $unitId);
    exit;
}

$currentThumbnail = (string)($currentUnit['thumbnail'] ?? '');
$thumbnailForDatabase = $currentThumbnail !== '' ? $currentThumbnail : null;

if ($newThumbnail !== null) {
    $thumbnailForDatabase = $newThumbnail;
} elseif ($removeThumbnail) {
    $thumbnailForDatabase = null;
}

try {
    $pdo->beginTransaction();

    $updateStmt = $pdo->prepare(
        "UPDATE units
         SET
            book_id = ?,
            unit_number = ?,
            title = ?,
            thumbnail = ?,
            description = ?,
            required_xp = ?,
            sort_order = ?,
            status = ?,
            updated_at = NOW()
         WHERE id = ?"
    );

    $updateStmt->execute([
        $bookId,
        $unitNumber,
        $title,
        $thumbnailForDatabase,
        $description !== '' ? $description : null,
        $requiredXp,
        $sortOrder,
        $status,
        $unitId,
    ]);

    $pdo->commit();

    // Remove the old file only after a successful database update.
    if ($newThumbnail !== null && $currentThumbnail !== '') {
        deleteUnitThumbnailFile($currentThumbnail);
    } elseif ($removeThumbnail && $currentThumbnail !== '') {
        deleteUnitThumbnailFile($currentThumbnail);
    }

    $_SESSION['units_message'] = 'Unit updated successfully.';
    $_SESSION['units_message_type'] = 'success';

    header('Location: index.php?book_id=' . $bookId);
    exit;
} catch (Throwable $e) {
    if ($pdo->inTransaction()) {
        $pdo->rollBack();
    }

    // Remove the newly uploaded file because it was not committed to the database.
    if ($newThumbnail !== null) {
        deleteUnitThumbnailFile($newThumbnail);
    }

    $_SESSION['units_old'] = $old;

    if ($e instanceof PDOException && (string)$e->getCode() === '23000') {
        $_SESSION['units_errors'] = [
            'This Unit Number already exists in the selected Book.',
        ];
    } else {
        $_SESSION['units_errors'] = [
            'Could not update the Unit. Please try again.',
        ];
    }

    header('Location: edit.php?id=' . $unitId);
    exit;
}
