<?php

declare(strict_types=1);

namespace Admin\Controllers;

use App\Core\Controller;

/**
 * Admin News Controller
 *
 * CRUD operations for branch news / general institute news.
 * When branch_id is NULL the article is treated as general
 * institute news (not tied to any specific branch).
 */
class AdminNewsController extends AdminController
{
    /**
     * List all news articles with pagination, search and filter.
     *
     * @param array<string, string> $params Route parameters
     * @return void
     */
    public function index(array $params = []): void
    {
        requireAdmin();

        $page    = max(1, (int) ($_GET['page'] ?? 1));
        $perPage = 15;
        $offset  = ($page - 1) * $perPage;

        // Search & filter
        $search    = trim($_GET['search'] ?? '');
        $branchId  = $_GET['branch_id'] ?? '';
        $status    = $_GET['status'] ?? '';

        // Build WHERE clauses
        $where  = ['1=1'];
        $binds  = [];

        if ($search !== '') {
            $where[]        = '(bn.title LIKE :search OR bn.slug LIKE :search)';
            $binds[':search'] = '%' . $search . '%';
        }

        if ($branchId !== '') {
            if ($branchId === 'general') {
                $where[] = 'bn.branch_id IS NULL';
            } else {
                $where[]          = 'bn.branch_id = :branch_id';
                $binds[':branch_id'] = (int) $branchId;
            }
        }

        if ($status !== '') {
            $where[]          = 'bn.active = :status';
            $binds[':status'] = (int) $status;
        }

        $whereClause = implode(' AND ', $where);

        // Count total
        $countSql  = "SELECT COUNT(*) AS total FROM `branch_news` bn WHERE {$whereClause}";
        $countStmt = $this->db->prepare($countSql);
        $countStmt->execute($binds);
        $totalNews   = (int) ($countStmt->fetch()['total'] ?? 0);
        $totalPages  = (int) ceil($totalNews / $perPage);

        // Fetch paginated results
        $sql = "SELECT bn.*, b.name AS branch_name
                FROM `branch_news` bn
                LEFT JOIN `branches` b ON bn.branch_id = b.id
                WHERE {$whereClause}
                ORDER BY bn.created_at DESC
                LIMIT :limit OFFSET :offset";

        $stmt = $this->db->prepare($sql);
        foreach ($binds as $key => $value) {
            $stmt->bindValue($key, $value);
        }
        $stmt->bindValue(':limit', $perPage, \PDO::PARAM_INT);
        $stmt->bindValue(':offset', $offset, \PDO::PARAM_INT);
        $stmt->execute();

        $news = $stmt->fetchAll() ?: [];

        // Get branches for filter dropdown
        $branchStmt = $this->db->query('SELECT `id`, `name` FROM `branches` ORDER BY `name` ASC');
        $branches = $branchStmt->fetchAll() ?: [];

        $this->adminView('news', [
            'title'       => 'Manage News',
            'currentPage' => 'news',
            'news'        => $news,
            'branches'    => $branches,
            'search'      => $search,
            'filterBranch' => $branchId,
            'filterStatus' => $status,
            'page'        => $page,
            'totalPages'  => $totalPages,
            'totalNews'   => $totalNews,
        ]);
    }

    /**
     * Show the create news form.
     *
     * @param array<string, string> $params Route parameters
     * @return void
     */
    public function create(array $params = []): void
    {
        requireAdmin();

        $branchStmt = $this->db->query('SELECT `id`, `name` FROM `branches` ORDER BY `name` ASC');
        $branches = $branchStmt->fetchAll() ?: [];

        $this->adminView('news_form', [
            'title'       => 'Add New News',
            'currentPage' => 'news',
            'newsItem'    => null,
            'branches'    => $branches,
        ]);
    }

    /**
     * Store a new news article.
     *
     * @param array<string, string> $params Route parameters
     * @return void
     */
    public function store(array $params = []): void
    {
        requireAdmin();
        $this->validateCsrf();

        $title     = sanitize($_POST['title'] ?? '');
        $titleHi   = trim($_POST['title_hi'] ?? '');
        $content   = $_POST['content'] ?? '';
        $contentHi = $_POST['content_hi'] ?? '';
        $branchId  = ($_POST['branch_id'] ?? '') !== '' ? (int) $_POST['branch_id'] : null;
        $active    = isset($_POST['active']) ? 1 : 0;

        if (empty($title)) {
            flash('error', 'News title is required.');
            redirect(BASE_PATH . '/admin/news/create');
        }

        if (empty($content)) {
            flash('error', 'News content is required.');
            redirect(BASE_PATH . '/admin/news/create');
        }

        // Auto-generate slug from title
        $slug = $this->generateUniqueSlug($title);

        // Handle image upload
        $imagePath = $this->handleImageUpload('image', 'news');

        $stmt = $this->db->prepare(
            'INSERT INTO `branch_news` (`branch_id`, `title`, `title_hi`, `slug`, `content`, `content_hi`, `image`, `active`)
             VALUES (:branch_id, :title, :title_hi, :slug, :content, :content_hi, :image, :active)'
        );

        $stmt->execute([
            ':branch_id'  => $branchId,
            ':title'      => $title,
            ':title_hi'   => $titleHi ?: null,
            ':slug'       => $slug,
            ':content'    => $content,
            ':content_hi' => $contentHi ?: null,
            ':image'      => $imagePath,
            ':active'     => $active,
        ]);

        flash('success', 'News article created successfully.');
        redirect(BASE_PATH . '/admin/news');
    }

    /**
     * Show the edit news form.
     *
     * @param array<string, string> $params Route parameters
     * @return void
     */
    public function edit(array $params = []): void
    {
        requireAdmin();

        $id = (int) ($params['id'] ?? 0);

        $stmt = $this->db->prepare('SELECT * FROM `branch_news` WHERE `id` = :id LIMIT 1');
        $stmt->execute([':id' => $id]);
        $newsItem = $stmt->fetch() ?: null;

        if ($newsItem === null) {
            flash('error', 'News article not found.');
            redirect(BASE_PATH . '/admin/news');
        }

        $branchStmt = $this->db->query('SELECT `id`, `name` FROM `branches` ORDER BY `name` ASC');
        $branches = $branchStmt->fetchAll() ?: [];

        $this->adminView('news_form', [
            'title'       => 'Edit News',
            'currentPage' => 'news',
            'newsItem'    => $newsItem,
            'branches'    => $branches,
        ]);
    }

    /**
     * Update an existing news article.
     *
     * @param array<string, string> $params Route parameters
     * @return void
     */
    public function update(array $params = []): void
    {
        requireAdmin();
        $this->validateCsrf();

        $id = (int) ($params['id'] ?? 0);

        $stmt = $this->db->prepare('SELECT * FROM `branch_news` WHERE `id` = :id LIMIT 1');
        $stmt->execute([':id' => $id]);
        $newsItem = $stmt->fetch() ?: null;

        if ($newsItem === null) {
            flash('error', 'News article not found.');
            redirect(BASE_PATH . '/admin/news');
        }

        $title     = sanitize($_POST['title'] ?? '');
        $titleHi   = trim($_POST['title_hi'] ?? '');
        $content   = $_POST['content'] ?? '';
        $contentHi = $_POST['content_hi'] ?? '';
        $branchId  = ($_POST['branch_id'] ?? '') !== '' ? (int) $_POST['branch_id'] : null;
        $active    = isset($_POST['active']) ? 1 : 0;

        if (empty($title)) {
            flash('error', 'News title is required.');
            redirect(BASE_PATH . '/admin/news/' . $id . '/edit');
        }

        if (empty($content)) {
            flash('error', 'News content is required.');
            redirect(BASE_PATH . '/admin/news/' . $id . '/edit');
        }

        // Regenerate slug only if title changed
        $slug = $newsItem['slug'];
        if ($title !== $newsItem['title']) {
            $slug = $this->generateUniqueSlug($title, $id);
        }

        // Handle optional image replacement
        $imagePath = $this->handleImageUpload('image', 'news');
        if ($imagePath !== null) {
            // New image uploaded — delete the old one
            $this->deleteImageFile($newsItem['image'] ?? null);
        } else {
            $imagePath = $newsItem['image'];
        }

        $stmt = $this->db->prepare(
            'UPDATE `branch_news` SET
                `branch_id`  = :branch_id,
                `title`      = :title,
                `title_hi`   = :title_hi,
                `slug`       = :slug,
                `content`    = :content,
                `content_hi` = :content_hi,
                `image`      = :image,
                `active`     = :active
             WHERE `id` = :id'
        );

        $stmt->execute([
            ':branch_id'  => $branchId,
            ':title'      => $title,
            ':title_hi'   => $titleHi ?: null,
            ':slug'       => $slug,
            ':content'    => $content,
            ':content_hi' => $contentHi ?: null,
            ':image'      => $imagePath,
            ':active'     => $active,
            ':id'         => $id,
        ]);

        flash('success', 'News article updated successfully.');
        redirect(BASE_PATH . '/admin/news');
    }

    /**
     * Delete a news article.
     *
     * @param array<string, string> $params Route parameters
     * @return void
     */
    public function delete(array $params = []): void
    {
        requireAdmin();
        $this->validateCsrf();

        $id = (int) ($params['id'] ?? 0);

        // Fetch the news item first to delete its image file
        $stmt = $this->db->prepare('SELECT * FROM `branch_news` WHERE `id` = :id LIMIT 1');
        $stmt->execute([':id' => $id]);
        $newsItem = $stmt->fetch() ?: null;

        if ($newsItem !== null) {
            $this->deleteImageFile($newsItem['image'] ?? null);
        }

        $stmt = $this->db->prepare('DELETE FROM `branch_news` WHERE `id` = :id');
        $stmt->execute([':id' => $id]);

        if ($stmt->rowCount() > 0) {
            flash('success', 'News article deleted successfully.');
        } else {
            flash('warning', 'News article not found or already deleted.');
        }
        redirect(BASE_PATH . '/admin/news');
    }

    /**
     * Toggle the active/publish status of a news article.
     *
     * @param array<string, string> $params Route parameters
     * @return void
     */
    public function togglePublish(array $params = []): void
    {
        requireAdmin();
        $this->validateCsrf();

        $id = (int) ($params['id'] ?? 0);

        $stmt = $this->db->prepare('SELECT `active` FROM `branch_news` WHERE `id` = :id LIMIT 1');
        $stmt->execute([':id' => $id]);
        $newsItem = $stmt->fetch() ?: null;

        if ($newsItem === null) {
            flash('error', 'News article not found.');
            redirect(BASE_PATH . '/admin/news');
        }

        $newStatus = $newsItem['active'] ? 0 : 1;

        $updateStmt = $this->db->prepare('UPDATE `branch_news` SET `active` = :active WHERE `id` = :id');
        $updateStmt->execute([':active' => $newStatus, ':id' => $id]);

        flash('success', $newStatus ? 'News article published.' : 'News article unpublished.');
        redirect(BASE_PATH . '/admin/news');
    }

    /**
     * Generate a unique slug from the given title.
     *
     * Appends a numeric suffix if the slug already exists in the database,
     * optionally excluding a specific news ID (used when updating).
     *
     * @param string $title   The title to slugify
     * @param int    $excludeId News ID to exclude from uniqueness check
     * @return string A unique slug
     */
    private function generateUniqueSlug(string $title, int $excludeId = 0): string
    {
        $slug = slugify($title);

        if ($slug === '') {
            $slug = 'news-' . time();
        }

        $originalSlug = $slug;
        $counter = 1;

        while (true) {
            $sql = 'SELECT COUNT(*) AS cnt FROM `branch_news` WHERE `slug` = :slug';
            $binds = [':slug' => $slug];

            if ($excludeId > 0) {
                $sql .= ' AND `id` != :exclude_id';
                $binds[':exclude_id'] = $excludeId;
            }

            $stmt = $this->db->prepare($sql);
            $stmt->execute($binds);
            $count = (int) $stmt->fetch()['cnt'];

            if ($count === 0) {
                break;
            }

            $counter++;
            $slug = $originalSlug . '-' . $counter;
        }

        return $slug;
    }
}
