<?php
declare(strict_types=1);

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

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

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

function input_json(): array
{
    $raw = file_get_contents('php://input');
    if ($raw === false || trim($raw) === '') {
        return [];
    }

    $data = json_decode($raw, true);
    return is_array($data) ? $data : [];
}

function route_path(): string
{
    $path = parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH) ?: '';
    $pos = strpos($path, '/api');
    if ($pos !== false) {
        $path = substr($path, $pos + 4);
    }

    $path = trim($path, '/');
    return $path === 'index.php' ? '' : $path;
}

function page_limit(): array
{
    $page = max(1, (int)($_GET['page'] ?? 1));
    $limit = max(1, min(100, (int)($_GET['limit'] ?? 12)));
    return [$page, $limit, ($page - 1) * $limit];
}

function excerpt(string $html, int $length = 160): string
{
    $text = trim(preg_replace('/\s+/', ' ', strip_tags($html)) ?? '');
    $textLength = function_exists('mb_strlen') ? mb_strlen($text) : strlen($text);
    if ($textLength <= $length) {
        return $text;
    }

    $shortText = function_exists('mb_substr') ? mb_substr($text, 0, $length - 3) : substr($text, 0, $length - 3);
    return $shortText . '...';
}

function auth_user(): ?array
{
    $headers = function_exists('getallheaders') ? getallheaders() : [];
    $token = $headers['Authorization'] ?? $headers['authorization'] ?? '';
    $token = trim(str_replace('Bearer ', '', $token));

    if ($token === '') {
        return null;
    }

    $stmt = db()->prepare(
        'SELECT u.id, u.username, u.role
         FROM user_sessions s
         INNER JOIN users u ON u.id = s.user_id
         WHERE s.token = :token AND s.expires_at > NOW()
         LIMIT 1'
    );
    $stmt->execute(['token' => $token]);
    $user = $stmt->fetch();

    return $user ?: null;
}

function require_auth(): array
{
    $user = auth_user();
    if (!$user) {
        respond(['success' => false, 'message' => 'Unauthorized'], 401);
    }

    return $user;
}

function admin_mode(): bool
{
    return auth_user() !== null;
}

function required_string(array $data, string $key, string $label): string
{
    $value = trim((string)($data[$key] ?? ''));
    if ($value === '') {
        respond(['success' => false, 'message' => $label . ' is required'], 422);
    }

    return $value;
}

function slug_value(string $value): string
{
    $slug = strtolower(trim($value));
    $slug = preg_replace('/[^a-z0-9\s-]/', '', $slug) ?? '';
    $slug = preg_replace('/[\s-]+/', '-', $slug) ?? '';
    return trim($slug, '-');
}

function unique_exists(PDO $pdo, string $table, string $field, string $value, string $idField, int $ignoreId = 0): bool
{
    $sql = "SELECT COUNT(*) FROM $table WHERE $field = :value";
    $params = ['value' => $value];

    if ($ignoreId > 0) {
        $sql .= " AND $idField <> :id";
        $params['id'] = $ignoreId;
    }

    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);
    return (int)$stmt->fetchColumn() > 0;
}

try {
    $pdo = db();
    $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
    $route = route_path();

    if ($route === 'login' && $method === 'POST') {
        $data = input_json();
        $username = trim((string)($data['username'] ?? ''));
        $password = (string)($data['password'] ?? '');

        $stmt = $pdo->prepare('SELECT id, username, password_hash, role FROM users WHERE username = :username LIMIT 1');
        $stmt->execute(['username' => $username]);
        $user = $stmt->fetch();

        $storedPassword = $user ? (string)$user['password_hash'] : '';
        // $valid = $user && (
        //     hash_equals($storedPassword, hash('sha256', $password)) ||
        //     password_verify($password, $storedPassword)
        // );

        $valid = $user && password_verify($password, $storedPassword);
        
        if (!$valid) {
            respond(['success' => false, 'message' => 'Invalid username or password'], 401);
        }

        $token = bin2hex(random_bytes(32));
        $expires = (new DateTimeImmutable('+1 day'))->format('Y-m-d H:i:s');
        $stmt = $pdo->prepare('INSERT INTO user_sessions (user_id, token, expires_at) VALUES (:user_id, :token, :expires_at)');
        $stmt->execute([
            'user_id' => $user['id'],
            'token' => $token,
            'expires_at' => $expires,
        ]);

        respond([
            'success' => true,
            'token' => $token,
            'user' => [
                'id' => (int)$user['id'],
                'username' => $user['username'],
                'role' => $user['role'],
            ],
        ]);
    }

    if ($route === 'categories' && $method === 'GET') {
        $stmt = $pdo->query('SELECT id, name, slug, created_at FROM categories ORDER BY name ASC');
        respond($stmt->fetchAll());
    }

    if ($route === 'post-category' && $method === 'POST') {
        require_auth();
        $data = input_json();
        $name = required_string($data, 'name', 'Category name');
        $slug = slug_value((string)($data['slug'] ?? $name));

        if ($slug === '') {
            respond(['success' => false, 'message' => 'Category slug is required'], 422);
        }
        if (unique_exists($pdo, 'categories', 'slug', $slug, 'id')) {
            respond(['success' => false, 'message' => 'Category slug already exists'], 409);
        }

        $stmt = $pdo->prepare('INSERT INTO categories (name, slug, created_at) VALUES (:name, :slug, NOW())');
        $stmt->execute(['name' => $name, 'slug' => $slug]);
        respond(['success' => true, 'id' => (int)$pdo->lastInsertId()]);
    }

    if ($route === 'update-category' && $method === 'PUT') {
        require_auth();
        $data = input_json();
        $id = (int)($data['id'] ?? 0);
        if ($id <= 0) {
            respond(['success' => false, 'message' => 'Category ID is required'], 422);
        }

        $name = required_string($data, 'name', 'Category name');
        $slug = slug_value((string)($data['slug'] ?? $name));
        if (unique_exists($pdo, 'categories', 'slug', $slug, 'id', $id)) {
            respond(['success' => false, 'message' => 'Category slug already exists'], 409);
        }

        $stmt = $pdo->prepare('UPDATE categories SET name = :name, slug = :slug WHERE id = :id');
        $stmt->execute(['name' => $name, 'slug' => $slug, 'id' => $id]);
        respond(['success' => true]);
    }

    if ($route === 'delete-category' && $method === 'DELETE') {
        require_auth();
        $id = (int)($_GET['id'] ?? 0);
        if ($id <= 0) {
            respond(['success' => false, 'message' => 'Category ID is required'], 422);
        }

        $stmt = $pdo->prepare('DELETE FROM categories WHERE id = :id');
        $stmt->execute(['id' => $id]);
        respond(['success' => true]);
    }

    if ($route === 'blogs' && $method === 'GET') {
        [$page, $limit, $offset] = page_limit();
        $categoryId = (int)($_GET['category_id'] ?? 0);
        $categorySlug = trim((string)($_GET['category_slug'] ?? ''));
        $isAdmin = admin_mode();
        $where = $isAdmin ? 'WHERE 1=1' : "WHERE b.status = 'published'";
        $params = [];

        if ($categoryId > 0) {
            $where .= ' AND b.category_id = :category_id';
            $params['category_id'] = $categoryId;
        } elseif ($categorySlug !== '') {
            $where .= ' AND c.slug = :category_slug';
            $params['category_slug'] = $categorySlug;
        }

        $countStmt = $pdo->prepare("SELECT COUNT(*) FROM blogs b LEFT JOIN categories c ON c.id = b.category_id $where");
        $countStmt->execute($params);
        $total = (int)$countStmt->fetchColumn();

        $sql = "SELECT b.blogid, b.blog_title, b.blog_content, b.blogslug, b.img, b.category_id,
                       b.tags, b.status, b.views, b.likes, b.created_at, b.updated_at,
                       c.name AS category_name, c.slug AS category_slug
                FROM blogs b
                LEFT JOIN categories c ON c.id = b.category_id
                $where
                ORDER BY b.created_at DESC
                LIMIT :limit OFFSET :offset";
        $stmt = $pdo->prepare($sql);
        foreach ($params as $key => $value) {
            $type = $key === 'category_id' ? PDO::PARAM_INT : PDO::PARAM_STR;
            $stmt->bindValue(':' . $key, $value, $type);
        }
        $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
        $stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
        $stmt->execute();

        $blogs = array_map(static function (array $blog): array {
            $blog['excerpt'] = excerpt((string)($blog['blog_content'] ?? ''));
            return $blog;
        }, $stmt->fetchAll());

        respond([
            'blogs' => $blogs,
            'page' => $page,
            'limit' => $limit,
            'total' => $total,
            'totalPages' => (int)ceil($total / $limit),
        ]);
    }

    if ($route === 'blog' && $method === 'GET') {
        $slug = trim((string)($_GET['slug'] ?? ''));
        $id = (int)($_GET['id'] ?? 0);
        $statusSql = admin_mode() ? '' : " AND b.status = 'published'";

        if ($slug !== '') {
            $stmt = $pdo->prepare(
                "SELECT b.*, c.name AS category_name, c.slug AS category_slug
                 FROM blogs b
                 LEFT JOIN categories c ON c.id = b.category_id
                 WHERE b.blogslug = :slug $statusSql
                 LIMIT 1"
            );
            $stmt->execute(['slug' => $slug]);
        } else {
            $stmt = $pdo->prepare(
                "SELECT b.*, c.name AS category_name, c.slug AS category_slug
                 FROM blogs b
                 LEFT JOIN categories c ON c.id = b.category_id
                 WHERE b.blogid = :id $statusSql
                 LIMIT 1"
            );
            $stmt->execute(['id' => $id]);
        }

        $blog = $stmt->fetch();
        if (!$blog) {
            respond(['success' => false, 'message' => 'Blog not found'], 404);
        }

        respond(['success' => true, 'blog' => $blog] + $blog);
    }

    if ($route === 'medications' && $method === 'GET') {
        [$page, $limit, $offset] = page_limit();
        $letter = strtoupper(substr((string)($_GET['letter'] ?? ''), 0, 1));
        $isAdmin = admin_mode();
        $where = $isAdmin ? 'WHERE 1=1' : "WHERE status = 'published'";
        $params = [];

        if ($letter !== '' && preg_match('/^[A-Z]$/', $letter)) {
            $where .= ' AND UPPER(TRIM(titleTag)) LIKE :letter';
            $params['letter'] = $letter . '%';
        }

        $countStmt = $pdo->prepare("SELECT COUNT(*) FROM medications $where");
        $countStmt->execute($params);
        $total = (int)$countStmt->fetchColumn();

        $stmt = $pdo->prepare(
            "SELECT medicationsid, metatitle, metadescription, titleTag, title, content, slug, img,
                    tags, status, views, likes, created_at, updated_at
             FROM medications
             $where
             ORDER BY LOWER(TRIM(titleTag)) ASC, medicationsid ASC
             LIMIT :limit OFFSET :offset"
        );
        foreach ($params as $key => $value) {
            $stmt->bindValue(':' . $key, $value);
        }
        $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
        $stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
        $stmt->execute();

        $medications = array_map(static function (array $medication): array {
            $medication['excerpt'] = excerpt((string)($medication['content'] ?? ''));
            return $medication;
        }, $stmt->fetchAll());

        respond([
            'medications' => $medications,
            'blogs' => $medications,
            'page' => $page,
            'limit' => $limit,
            'total' => $total,
            'totalPages' => (int)ceil($total / $limit),
        ]);
    }

    if ($route === 'medication' && $method === 'GET') {
        $slug = trim((string)($_GET['slug'] ?? ''));
        $id = (int)($_GET['id'] ?? 0);
        $statusSql = admin_mode() ? '' : " AND status = 'published'";

        if ($slug !== '') {
            $stmt = $pdo->prepare("SELECT * FROM medications WHERE slug = :slug $statusSql LIMIT 1");
            $stmt->execute(['slug' => $slug]);
        } else {
            $stmt = $pdo->prepare("SELECT * FROM medications WHERE medicationsid = :id $statusSql LIMIT 1");
            $stmt->execute(['id' => $id]);
        }

        $medication = $stmt->fetch();
        if (!$medication) {
            respond(['success' => false, 'message' => 'Medication not found'], 404);
        }

        respond(['success' => true, 'medication' => $medication] + $medication);
    }

    if ($route === 'post-blog' && $method === 'POST') {
        require_auth();
        $data = input_json();

        $title = required_string($data, 'blog_title', 'Blog title');
        $slug = slug_value((string)($data['blogslug'] ?? $title));
        if ($slug === '') {
            respond(['success' => false, 'message' => 'Blog slug is required'], 422);
        }
        if (unique_exists($pdo, 'blogs', 'blogslug', $slug, 'blogid')) {
            respond(['success' => false, 'message' => 'Blog slug already exists'], 409);
        }

        $stmt = $pdo->prepare(
            'INSERT INTO blogs
             (ns_blogmetatitle, ns_blogmetadescription, blog_title, blog_content, blogslug, img,
              category_id, tags, status, views, likes, created_at, updated_at)
             VALUES
             (:meta_title, :meta_description, :title, :content, :slug, :img,
              :category_id, :tags, :status, 0, 0, NOW(), NOW())'
        );
        $stmt->execute([
            'meta_title' => trim((string)($data['ns_blogmetatitle'] ?? '')),
            'meta_description' => trim((string)($data['ns_blogmetadescription'] ?? '')),
            'title' => $title,
            'content' => (string)($data['blog_content'] ?? ''),
            'slug' => $slug,
            'img' => (string)($data['img'] ?? ''),
            'category_id' => (int)($data['category_id'] ?? 0) ?: null,
            'tags' => trim((string)($data['tags'] ?? '')),
            'status' => trim((string)($data['status'] ?? 'draft')) ?: 'draft',
        ]);

        respond(['success' => true, 'id' => (int)$pdo->lastInsertId()]);
    }

    if ($route === 'update-blog' && $method === 'PUT') {
        require_auth();
        $data = input_json();
        $id = (int)($data['blogid'] ?? $data['id'] ?? 0);
        if ($id <= 0) {
            respond(['success' => false, 'message' => 'Blog ID is required'], 422);
        }

        $title = required_string($data, 'blog_title', 'Blog title');
        $slug = slug_value((string)($data['blogslug'] ?? $title));
        if (unique_exists($pdo, 'blogs', 'blogslug', $slug, 'blogid', $id)) {
            respond(['success' => false, 'message' => 'Blog slug already exists'], 409);
        }

        $stmt = $pdo->prepare(
            'UPDATE blogs
             SET ns_blogmetatitle = :meta_title,
                 ns_blogmetadescription = :meta_description,
                 blog_title = :title,
                 blog_content = :content,
                 blogslug = :slug,
                 img = :img,
                 category_id = :category_id,
                 tags = :tags,
                 status = :status,
                 updated_at = NOW()
             WHERE blogid = :id'
        );
        $stmt->execute([
            'meta_title' => trim((string)($data['ns_blogmetatitle'] ?? '')),
            'meta_description' => trim((string)($data['ns_blogmetadescription'] ?? '')),
            'title' => $title,
            'content' => (string)($data['blog_content'] ?? ''),
            'slug' => $slug,
            'img' => (string)($data['img'] ?? ''),
            'category_id' => (int)($data['category_id'] ?? 0) ?: null,
            'tags' => trim((string)($data['tags'] ?? '')),
            'status' => trim((string)($data['status'] ?? 'draft')) ?: 'draft',
            'id' => $id,
        ]);

        respond(['success' => true]);
    }

    if ($route === 'delete-blog' && $method === 'DELETE') {
        require_auth();
        $id = (int)($_GET['id'] ?? 0);
        if ($id <= 0) {
            respond(['success' => false, 'message' => 'Blog ID is required'], 422);
        }

        $stmt = $pdo->prepare('DELETE FROM blogs WHERE blogid = :id');
        $stmt->execute(['id' => $id]);
        respond(['success' => true]);
    }

    if ($route === 'post-medication' && $method === 'POST') {
        require_auth();
        $data = input_json();

        $title = required_string($data, 'title', 'Title');
        $titleTag = required_string($data, 'titleTag', 'Title tag');
        $slug = slug_value((string)($data['slug'] ?? $title));
        if ($slug === '') {
            respond(['success' => false, 'message' => 'Medication slug is required'], 422);
        }
        if (unique_exists($pdo, 'medications', 'slug', $slug, 'medicationsid')) {
            respond(['success' => false, 'message' => 'Medication slug already exists'], 409);
        }

        $stmt = $pdo->prepare(
            'INSERT INTO medications
             (metatitle, metadescription, titleTag, content, slug, img, tags, status,
              views, likes, created_at, updated_at, title)
             VALUES
             (:meta_title, :meta_description, :title_tag, :content, :slug, :img, :tags, :status,
              0, 0, NOW(), NOW(), :title)'
        );
        $stmt->execute([
            'meta_title' => trim((string)($data['metatitle'] ?? '')),
            'meta_description' => trim((string)($data['metadescription'] ?? '')),
            'title_tag' => $titleTag,
            'content' => (string)($data['content'] ?? ''),
            'slug' => $slug,
            'img' => (string)($data['img'] ?? ''),
            'tags' => trim((string)($data['tags'] ?? '')),
            'status' => trim((string)($data['status'] ?? 'draft')) ?: 'draft',
            'title' => $title,
        ]);

        respond(['success' => true, 'id' => (int)$pdo->lastInsertId()]);
    }

    if ($route === 'update-medication' && $method === 'PUT') {
        require_auth();
        $data = input_json();
        $id = (int)($data['id'] ?? $data['medicationsid'] ?? 0);
        if ($id <= 0) {
            respond(['success' => false, 'message' => 'Medication ID is required'], 422);
        }

        $title = required_string($data, 'title', 'Title');
        $titleTag = required_string($data, 'titleTag', 'Title tag');
        $slug = slug_value((string)($data['slug'] ?? $title));
        if (unique_exists($pdo, 'medications', 'slug', $slug, 'medicationsid', $id)) {
            respond(['success' => false, 'message' => 'Medication slug already exists'], 409);
        }

        $stmt = $pdo->prepare(
            'UPDATE medications
             SET metatitle = :meta_title,
                 metadescription = :meta_description,
                 titleTag = :title_tag,
                 content = :content,
                 slug = :slug,
                 img = :img,
                 tags = :tags,
                 status = :status,
                 updated_at = NOW(),
                 title = :title
             WHERE medicationsid = :id'
        );
        $stmt->execute([
            'meta_title' => trim((string)($data['metatitle'] ?? '')),
            'meta_description' => trim((string)($data['metadescription'] ?? '')),
            'title_tag' => $titleTag,
            'content' => (string)($data['content'] ?? ''),
            'slug' => $slug,
            'img' => (string)($data['img'] ?? ''),
            'tags' => trim((string)($data['tags'] ?? '')),
            'status' => trim((string)($data['status'] ?? 'draft')) ?: 'draft',
            'title' => $title,
            'id' => $id,
        ]);

        respond(['success' => true]);
    }

    if ($route === 'delete-medication' && $method === 'DELETE') {
        require_auth();
        $id = (int)($_GET['id'] ?? 0);
        if ($id <= 0) {
            respond(['success' => false, 'message' => 'Medication ID is required'], 422);
        }

        $stmt = $pdo->prepare('DELETE FROM medications WHERE medicationsid = :id');
        $stmt->execute(['id' => $id]);
        respond(['success' => true]);
    }

    if (($route === 'contacts' || $route === 'contact_messages') && $method === 'GET') {
        require_auth();
        $stmt = $pdo->query('SELECT id, name, email, phone, subject, message, created_at FROM contact_messages ORDER BY created_at DESC');
        respond($stmt->fetchAll());
    }

    if (($route === 'contacts' || $route === 'contact_messages') && $method === 'POST') {
        $data = input_json();
        if (!$data) {
            $data = $_POST;
        }

        $name = trim((string)($data['name'] ?? ''));
        $email = trim((string)($data['email'] ?? ''));
        $message = trim((string)($data['message'] ?? ''));

        if ($name === '' || $email === '' || $message === '') {
            respond(['success' => false, 'message' => 'Name, email and message are required'], 422);
        }

        $stmt = $pdo->prepare(
            'INSERT INTO contact_messages (name, email, phone, subject, message)
             VALUES (:name, :email, :phone, :subject, :message)'
        );
        $stmt->execute([
            'name' => $name,
            'email' => $email,
            'phone' => trim((string)($data['phone'] ?? '')),
            'subject' => trim((string)($data['subject'] ?? '')),
            'message' => $message,
        ]);

        respond(['success' => true, 'id' => (int)$pdo->lastInsertId()]);
    }

    if ($route === 'delete-contact' && $method === 'DELETE') {
        require_auth();
        $id = (int)($_GET['id'] ?? 0);
        if ($id <= 0) {
            respond(['success' => false, 'message' => 'Contact ID is required'], 422);
        }

        $stmt = $pdo->prepare('DELETE FROM contact_messages WHERE id = :id');
        $stmt->execute(['id' => $id]);
        respond(['success' => true]);
    }

    if ($route === 'users' && $method === 'GET') {
        require_auth();
        $stmt = $pdo->query('SELECT id, username, role, created_at FROM users ORDER BY id DESC');
        respond($stmt->fetchAll());
    }

    respond(['success' => false, 'message' => 'Endpoint not found'], 404);
} catch (Throwable $e) {
    respond(['success' => false, 'message' => $e->getMessage()], 500);
}
