<?php

declare(strict_types=1);

require_once __DIR__ . '/../db.php';
require_once __DIR__ . '/../auth.php';

header('Content-Type: application/json; charset=utf-8');

const VALID_THEMES = ['white', 'dark', 'purple', 'green', 'beige'];

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

function getInputData(): array
{
    $contentType = $_SERVER['CONTENT_TYPE'] ?? '';

    if (str_contains($contentType, 'application/json')) {
        $raw = file_get_contents('php://input');
        $data = json_decode($raw, true);

        return is_array($data) ? $data : [];
    }

    return $_POST;
}

function pictureDataUri(?string $picture): ?string
{
    if ($picture === null || $picture === '') {
        return null;
    }

    $info = @getimagesizefromstring($picture);
    $mime = is_array($info) && isset($info['mime']) ? $info['mime'] : 'image/png';

    return 'data:' . $mime . ';base64,' . base64_encode($picture);
}

function uploadedPicture(): ?string
{
    if (empty($_FILES['picture']) || !is_array($_FILES['picture'])) {
        return null;
    }

    $file = $_FILES['picture'];

    if (($file['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) {
        return null;
    }

    if (($file['error'] ?? UPLOAD_ERR_OK) !== UPLOAD_ERR_OK) {
        jsonResponse([
            'success' => false,
            'error' => 'Could not upload profile picture.'
        ], 400);
    }

    if (($file['size'] ?? 0) > 10 * 1024 * 1024) {
        jsonResponse([
            'success' => false,
            'error' => 'Profile picture must be 10 MB or smaller.'
        ], 400);
    }

    $tmpName = (string)($file['tmp_name'] ?? '');
    $picture = $tmpName !== '' ? file_get_contents($tmpName) : false;

    if ($picture === false) {
        jsonResponse([
            'success' => false,
            'error' => 'Could not read profile picture.'
        ], 400);
    }

    $info = @getimagesizefromstring($picture);
    $allowedTypes = [
        IMAGETYPE_PNG,
        IMAGETYPE_JPEG,
        IMAGETYPE_WEBP,
        IMAGETYPE_GIF
    ];

    if (!is_array($info) || !in_array($info[2] ?? null, $allowedTypes, true)) {
        jsonResponse([
            'success' => false,
            'error' => 'Profile picture must be a PNG, JPG, WEBP, or GIF image.'
        ], 400);
    }

    return $picture;
}

function getUserSetting(int $userId, string $settingName): ?string
{
    $stmt = db()->prepare(
        'SELECT setting_value
         FROM user_settings
         WHERE user_id = ?
           AND setting_name = ?
         LIMIT 1'
    );

    $stmt->execute([$userId, $settingName]);
    $value = $stmt->fetchColumn();

    return $value !== false ? (string)$value : null;
}

function setUserSetting(int $userId, string $settingName, string $settingValue): void
{
    $stmt = db()->prepare(
        'SELECT id
         FROM user_settings
         WHERE user_id = ?
           AND setting_name = ?
         LIMIT 1'
    );

    $stmt->execute([$userId, $settingName]);
    $settingId = $stmt->fetchColumn();

    if ($settingId) {
        $updateStmt = db()->prepare(
            'UPDATE user_settings
             SET setting_value = ?
             WHERE id = ?'
        );

        $updateStmt->execute([$settingValue, $settingId]);
        return;
    }

    $insertStmt = db()->prepare(
        'INSERT INTO user_settings (user_id, setting_name, setting_value)
         VALUES (?, ?, ?)'
    );

    $insertStmt->execute([$userId, $settingName, $settingValue]);
}

$user = requireApiAuth();

$api = $_GET['api'] ?? '';

switch ($api) {

    case 'ListUsers': {
        $stmt = db()->query(
            'SELECT id, name, email, picture
             FROM users
             ORDER BY name ASC, email ASC'
        );

        $users = array_map(static function (array $targetUser): array {
            $targetUser['picture'] = pictureDataUri($targetUser['picture']);

            $targetUser['id'] = (int)$targetUser['id'];

            return $targetUser;
        }, $stmt->fetchAll());

        jsonResponse([
            'success' => true,
            'users' => $users
        ]);
    }

    case 'UserInfo': {
        $userId = (int)($_GET['user_id'] ?? 0);

        if ($userId <= 0) {
            jsonResponse([
                'success' => false,
                'error' => 'Missing or invalid user_id.'
            ], 400);
        }

        $stmt = db()->prepare(
            'SELECT id, name, email, picture
             FROM users
             WHERE id = ?
             LIMIT 1'
        );

        $stmt->execute([$userId]);
        $targetUser = $stmt->fetch();

        if (!$targetUser) {
            jsonResponse([
                'success' => false,
                'error' => 'User not found.'
            ], 404);
        }

        $targetUser['picture'] = pictureDataUri($targetUser['picture']);
        $targetUser['settings'] = [
            'theme' => getUserSetting((int)$targetUser['id'], 'theme') ?? 'dark'
        ];

        jsonResponse([
            'success' => true,
            'user' => $targetUser
        ]);
    }

    case 'Edit': {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            jsonResponse([
                'success' => false,
                'error' => 'Edit requires POST.'
            ], 405);
        }

        $userId = (int)($_GET['user_id'] ?? 0);

        if ($userId <= 0) {
            jsonResponse([
                'success' => false,
                'error' => 'Missing or invalid user_id.'
            ], 400);
        }

        if ($userId !== (int)$user['id']) {
            jsonResponse([
                'success' => false,
                'error' => 'You can only edit your own user.'
            ], 403);
        }

        $data = getInputData();

        $fields = [];
        $values = [];

        if (array_key_exists('name', $data)) {
            $name = trim((string)$data['name']);

            if ($name === '') {
                jsonResponse([
                    'success' => false,
                    'error' => 'Name cannot be empty.'
                ], 400);
            }

            if (strlen($name) > 128) {
                jsonResponse([
                    'success' => false,
                    'error' => 'Name is too long.'
                ], 400);
            }

            $fields[] = 'name = ?';
            $values[] = $name;
        }

        if (array_key_exists('email', $data)) {
            $email = strtolower(trim((string)$data['email']));

            if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
                jsonResponse([
                    'success' => false,
                    'error' => 'Invalid email.'
                ], 400);
            }

            if (strlen($email) > 128) {
                jsonResponse([
                    'success' => false,
                    'error' => 'Email is too long.'
                ], 400);
            }

            $emailStmt = db()->prepare(
                'SELECT id
                 FROM users
                 WHERE email = ?
                   AND id <> ?
                 LIMIT 1'
            );

            $emailStmt->execute([$email, $userId]);

            if ($emailStmt->fetch()) {
                jsonResponse([
                    'success' => false,
                    'error' => 'Email is already in use.'
                ], 400);
            }

            $fields[] = 'email = ?';
            $values[] = $email;
        }

        if (array_key_exists('password', $data)) {
            $password = (string)$data['password'];

            if (strlen($password) < 8) {
                jsonResponse([
                    'success' => false,
                    'error' => 'Password must be at least 8 characters.'
                ], 400);
            }

            $fields[] = 'passwd = ?';
            $values[] = password_hash($password, PASSWORD_ARGON2ID);
        }

        $removePicture = ($data['remove_picture'] ?? '') === '1';
        $picture = $removePicture ? null : uploadedPicture();

        if ($picture !== null) {
            $fields[] = 'picture = ?';
            $values[] = $picture;
        }

        if ($removePicture) {
            $fields[] = 'picture = NULL';
        }

        $theme = null;

        if (array_key_exists('theme', $data)) {
            $theme = strtolower(trim((string)$data['theme']));

            if (!in_array($theme, VALID_THEMES, true)) {
                jsonResponse([
                    'success' => false,
                    'error' => 'Theme must be valid.'
                ], 400);
            }
        }

        if (empty($fields) && $theme === null) {
            jsonResponse([
                'success' => false,
                'error' => 'No editable fields provided.'
            ], 400);
        }

        try {
            if (!empty($fields)) {
                $values[] = $userId;

                $stmt = db()->prepare(
                    'UPDATE users
                     SET ' . implode(', ', $fields) . '
                     WHERE id = ?'
                );

                $stmt->execute($values);
            }

            if ($theme !== null) {
                setUserSetting($userId, 'theme', $theme);
            }

            jsonResponse([
                'success' => true,
                'user_id' => $userId
            ]);

        } catch (PDOException $e) {
            jsonResponse([
                'success' => false,
                'error' => 'Database error.'
            ], 500);
        }
    }

    default: {
        jsonResponse([
            'success' => false,
            'error' => 'Unknown API action.'
        ], 404);
    }
}
