<?php

namespace App\Controllers;

use App\Core\Auth;
use App\Core\Config;
use App\Core\Controller;
use App\Helpers\Logger;
use App\Helpers\Validator;
use App\Models\Article;
use App\Models\Site;
use App\Models\SiteSeoMetric;
use App\Models\Topic;
use App\Models\GlobalTopic;
use App\Services\InstallerService;
use App\Services\SiteSeoSyncService;
use App\Services\WordPressService;

class SiteController extends Controller
{
    public function index(): void
    {
        Auth::requireLogin();

        $sites = Site::findAll('name ASC');

        // Attach topic count for each site
        foreach ($sites as &$site) {
            $site['topic_count'] = Topic::count('site_id = :sid', ['sid' => $site['id']]);
            $site['published_article_count'] = Article::count(
                'site_id = :sid AND status = :status',
                [
                    'sid' => $site['id'],
                    'status' => 'published',
                ]
            );
        }

        $this->view('sites/index', ['sites' => $sites]);
    }

    public function create(): void
    {
        Auth::requireLogin();
        $globalTopics = GlobalTopic::findAllGrouped();
        $this->view('sites/create', ['globalTopics' => $globalTopics]);
    }

    public function store(): void
    {
        Auth::requireLogin();

        $validator = new Validator();
        $validator
            ->required('name', $this->input('name'), 'Nazwa')
            ->required('url', $this->input('url'), 'URL')
            ->url('url', $this->input('url'), 'URL')
            ->required('api_user', $this->input('api_user'), 'Użytkownik API')
            ->required('api_token', $this->input('api_token'), 'Token API');

        if (!$validator->isValid()) {
            $this->flash('danger', $validator->getFirstError());
            $this->redirect('/sites/create');
            return;
        }

        $siteId = Site::create([
            'name' => $this->input('name'),
            'url' => rtrim($this->input('url'), '/'),
            'semstorm_domain' => $this->input('semstorm_domain') ?: null,
            'dataforseo_domain' => $this->input('dataforseo_domain') ?: null,
            'api_user' => $this->input('api_user'),
            'api_token' => $this->input('api_token'),
            'publish_interval_hours' => (int) ($this->input('publish_interval_hours', 24)),
            'is_active' => $this->input('is_active') ? 1 : 0,
            'is_multisite' => $this->input('is_multisite') ? 1 : 0,
        ]);

        // Create topics from selected global topics
        $selectedTopics = $this->input('topics');
        if (is_array($selectedTopics)) {
            foreach ($selectedTopics as $globalTopicId) {
                $globalTopic = GlobalTopic::find((int) $globalTopicId);
                if ($globalTopic) {
                    Topic::create([
                        'site_id' => $siteId,
                        'global_topic_id' => (int) $globalTopicId,
                        'name' => $globalTopic['name'],
                        'description' => $globalTopic['description'] ?? '',
                        'is_active' => 1,
                    ]);
                }
            }
        }

        $this->flash('success', 'Strona została dodana.');
        $this->redirect("/sites/{$siteId}/edit");
    }

    public function edit(string $id): void
    {
        Auth::requireLogin();

        $site = Site::find((int) $id);
        if (!$site) {
            $this->flash('danger', 'Strona nie znaleziona.');
            $this->redirect('/sites');
            return;
        }

        $topics = Topic::findBySiteWithGlobal((int) $id);
        $globalTopics = GlobalTopic::findAllGrouped();
        $assignedGlobalIds = array_values(array_unique(array_map(
            static fn($v) => (int) $v,
            array_filter(array_column($topics, 'global_topic_id'))
        )));
        $assignedTopicNames = array_values(array_unique(array_filter(array_map(
            static fn($name) => mb_strtolower(trim((string) $name)),
            array_column($topics, 'name')
        ))));

        $this->view('sites/edit', [
            'site' => $site,
            'topics' => $topics,
            'globalTopics' => $globalTopics,
            'assignedGlobalIds' => $assignedGlobalIds,
            'assignedTopicNames' => $assignedTopicNames,
        ]);
    }

    public function update(string $id): void
    {
        Auth::requireLogin();

        $validator = new Validator();
        $validator
            ->required('name', $this->input('name'), 'Nazwa')
            ->required('url', $this->input('url'), 'URL')
            ->url('url', $this->input('url'), 'URL')
            ->required('api_user', $this->input('api_user'), 'Użytkownik API')
            ->required('api_token', $this->input('api_token'), 'Token API');

        if (!$validator->isValid()) {
            $this->flash('danger', $validator->getFirstError());
            $this->redirect("/sites/{$id}/edit");
            return;
        }

        Site::update((int) $id, [
            'name' => $this->input('name'),
            'url' => rtrim($this->input('url'), '/'),
            'semstorm_domain' => $this->input('semstorm_domain') ?: null,
            'dataforseo_domain' => $this->input('dataforseo_domain') ?: null,
            'api_user' => $this->input('api_user'),
            'api_token' => $this->input('api_token'),
            'publish_interval_hours' => (int) ($this->input('publish_interval_hours', 24)),
            'is_active' => $this->input('is_active') ? 1 : 0,
            'is_multisite' => $this->input('is_multisite') ? 1 : 0,
            'ftp_host' => $this->input('ftp_host') ?: null,
            'ftp_port' => $this->input('ftp_port') ? (int) $this->input('ftp_port') : null,
            'ftp_user' => $this->input('ftp_user') ?: null,
            'ftp_pass' => $this->input('ftp_pass') ?: null,
            'ftp_path' => $this->input('ftp_path') ?: null,
            'db_host' => $this->input('db_host') ?: null,
            'db_name' => $this->input('db_name') ?: null,
            'db_user' => $this->input('db_user') ?: null,
            'db_pass' => $this->input('db_pass') ?: null,
            'db_prefix' => $this->input('db_prefix') ?: null,
            'wp_admin_user' => $this->input('wp_admin_user') ?: null,
            'wp_admin_pass' => $this->input('wp_admin_pass') ?: null,
            'wp_admin_email' => $this->input('wp_admin_email') ?: null,
        ]);

        $this->flash('success', 'Strona została zaktualizowana.');
        $this->redirect('/sites');
    }

    public function destroy(string $id): void
    {
        Auth::requireLogin();

        Site::delete((int) $id);

        $this->flash('success', 'Strona została usunięta.');
        $this->redirect('/sites');
    }

    public function testConnection(string $id): void
    {
        Auth::requireLogin();

        $site = Site::find((int) $id);
        if (!$site) {
            $this->json(['success' => false, 'message' => 'Strona nie znaleziona.']);
            return;
        }

        $wp = new WordPressService();
        $result = $wp->testConnection($site);

        $this->json($result);
    }

    public function dashboard(string $id): void
    {
        Auth::requireLogin();

        $site = Site::find((int) $id);
        if (!$site) {
            $this->flash('danger', 'Strona nie znaleziona.');
            $this->redirect('/sites');
            return;
        }

        $wp = new WordPressService();
        $permalinkStatus = $wp->getPermalinkSettings($site);
        $remoteServiceStatus = $wp->getRemoteServiceStatus($site);
        $commentSettings = $wp->getCommentSettings($site);

        $this->view('sites/dashboard', [
            'site' => $site,
            'permalinkStatus' => $permalinkStatus,
            'remoteServiceStatus' => $remoteServiceStatus,
            'commentSettings' => $commentSettings,
        ]);
    }

    public function comments(string $id): void
    {
        Auth::requireLogin();

        $site = Site::find((int) $id);
        if (!$site) {
            $this->flash('danger', 'Strona nie znaleziona.');
            $this->redirect('/sites');
            return;
        }

        $allowedStatuses = ['all', 'hold', 'approve', 'spam', 'trash'];
        $selectedStatus = (string) $this->input('status', 'all');
        if (!in_array($selectedStatus, $allowedStatuses, true)) {
            $selectedStatus = 'all';
        }

        $page = max(1, (int) $this->input('page', 1));
        $wp = new WordPressService();

        $this->view('sites/comments', [
            'site' => $site,
            'commentSettings' => $wp->getCommentSettings($site),
            'commentsResult' => $wp->getComments($site, $selectedStatus, $page),
            'selectedStatus' => $selectedStatus,
            'page' => $page,
        ]);
    }

    public function updateCommentsEnabled(string $id): void
    {
        Auth::requireLogin();

        $site = Site::find((int) $id);
        if (!$site) {
            $this->flash('danger', 'Strona nie znaleziona.');
            $this->redirect('/sites');
            return;
        }

        $enabled = (string) $this->input('enabled', '0') === '1';
        $wp = new WordPressService();
        $result = $wp->setCommentsEnabled($site, $enabled);

        if (!empty($result['success'])) {
            $this->flash('success', (string) ($result['message'] ?? 'Zmieniono ustawienia komentarzy.'));
        } else {
            $this->flash('danger', (string) ($result['message'] ?? 'Nie udalo sie zmienic ustawien komentarzy.'));
        }

        $this->redirect("/sites/{$id}/comments");
    }

    public function deleteComment(string $id, string $commentId): void
    {
        Auth::requireLogin();

        $site = Site::find((int) $id);
        if (!$site) {
            $this->flash('danger', 'Strona nie znaleziona.');
            $this->redirect('/sites');
            return;
        }

        $wp = new WordPressService();
        $result = $wp->deleteComment($site, (int) $commentId);

        if (!empty($result['success'])) {
            $this->flash('success', (string) ($result['message'] ?? 'Komentarz zostal usuniety.'));
        } else {
            $this->flash('danger', (string) ($result['message'] ?? 'Nie udalo sie usunac komentarza.'));
        }

        $status = (string) $this->input('status', 'all');
        $allowedStatuses = ['all', 'hold', 'approve', 'spam', 'trash'];
        $statusQuery = in_array($status, $allowedStatuses, true) ? '?status=' . urlencode($status) : '';
        $this->redirect("/sites/{$id}/comments{$statusQuery}");
    }

    public function seoPanel(string $id): void
    {
        Auth::requireLogin();

        $site = Site::find((int) $id);
        if (!$site) {
            $this->flash('danger', 'Strona nie znaleziona.');
            $this->redirect('/sites');
            return;
        }

        $seoMetrics = SiteSeoMetric::findBySite((int) $id, 12);
        $seoLatest = SiteSeoMetric::latestForSite((int) $id);

        $this->view('sites/seo', [
            'site' => $site,
            'seoMetrics' => $seoMetrics,
            'seoLatest' => $seoLatest,
        ]);
    }

    public function syncSeoMetrics(string $id): void
    {
        Auth::requireLogin();

        $site = Site::find((int) $id);
        if (!$site) {
            $this->flash('danger', 'Strona nie znaleziona.');
            $this->redirect('/sites');
            return;
        }

        $sync = new SiteSeoSyncService();
        $result = $sync->syncSite($site, null, true);

        if (!empty($result['success'])) {
            $this->flash('success', (string) ($result['message'] ?? 'Pobrano dane SEO.'));
        } else {
            $this->flash('danger', (string) ($result['message'] ?? 'Nie udalo sie pobrac danych SEO.'));
        }

        $this->redirect("/sites/{$id}/seo");
    }

    public function syncSeoByToken(): void
    {
        $configuredToken = (string) Config::get('SEO_TRIGGER_TOKEN', '');
        $providedToken = (string) $this->input('token', '');

        if ($providedToken === '') {
            $providedToken = (string) ($_SERVER['HTTP_X_SEO_TOKEN'] ?? '');
        }

        if ($configuredToken === '') {
            Logger::warning('Token SEO trigger called, but SEO_TRIGGER_TOKEN is not configured.', 'semstorm');
            $this->json(['success' => false, 'message' => 'Token trigger is disabled.'], 503);
            return;
        }

        if ($providedToken === '' || !hash_equals($configuredToken, $providedToken)) {
            $ip = (string) ($_SERVER['REMOTE_ADDR'] ?? 'unknown');
            Logger::warning("Invalid SEO token attempt from {$ip}", 'semstorm');
            $this->json(['success' => false, 'message' => 'Forbidden'], 403);
            return;
        }

        $force = ((int) $this->input('force', 0)) === 1;
        $siteId = (int) $this->input('site_id', 0);

        $sync = new SiteSeoSyncService();
        $saved = 0;
        $skipped = 0;
        $failed = 0;
        $details = [];

        if ($siteId > 0) {
            $site = Site::find($siteId);
            if (!$site) {
                $this->json(['success' => false, 'message' => 'Strona nie znaleziona.'], 404);
                return;
            }

            $result = $sync->syncSite($site, null, $force);
            $status = (string) ($result['status'] ?? 'error');

            if ($status === 'saved') {
                $saved++;
            } elseif ($status === 'skipped') {
                $skipped++;
            } else {
                $failed++;
            }

            $details[] = [
                'site_id' => (int) $site['id'],
                'site_name' => (string) $site['name'],
                'status' => $status,
                'message' => (string) ($result['message'] ?? ''),
            ];
        } elseif (!$force) {
            $metricMonth = (new \DateTimeImmutable('first day of this month'))->format('Y-m-01');
            $site = Site::findNextDueForSeoSync($metricMonth);

            if (!$site) {
                $this->json([
                    'success' => true,
                    'message' => 'SEMSTORM sync: brak stron do synchronizacji w tym miesiacu.',
                    'saved' => 0,
                    'skipped' => 0,
                    'failed' => 0,
                    'force' => false,
                    'details' => [],
                ], 200);
                return;
            }

            $result = $sync->syncSite($site, null, false);
            $status = (string) ($result['status'] ?? 'error');

            if ($status === 'saved') {
                $saved++;
            } elseif ($status === 'skipped') {
                $skipped++;
            } else {
                $failed++;
            }

            $details[] = [
                'site_id' => (int) $site['id'],
                'site_name' => (string) $site['name'],
                'status' => $status,
                'message' => (string) ($result['message'] ?? ''),
            ];
        } else {
            $sites = Site::findActive();

            foreach ($sites as $site) {
                $result = $sync->syncSite($site, null, $force);
                $status = (string) ($result['status'] ?? 'error');

                if ($status === 'saved') {
                    $saved++;
                } elseif ($status === 'skipped') {
                    $skipped++;
                } else {
                    $failed++;
                }

                $details[] = [
                    'site_id' => (int) $site['id'],
                    'site_name' => (string) $site['name'],
                    'status' => $status,
                    'message' => (string) ($result['message'] ?? ''),
                ];
            }
        }

        $this->json([
            'success' => $failed === 0,
            'message' => "SEMSTORM sync: saved={$saved}, skipped={$skipped}, failed={$failed}",
            'saved' => $saved,
            'skipped' => $skipped,
            'failed' => $failed,
            'force' => $force,
            'details' => $details,
        ], 200);
    }

    public function enablePrettyPermalinks(string $id): void
    {
        Auth::requireLogin();

        $site = Site::find((int) $id);
        if (!$site) {
            $this->flash('danger', 'Strona nie znaleziona.');
            $this->redirect('/sites');
            return;
        }

        $wp = new WordPressService();
        $result = $wp->enablePrettyPermalinks($site);

        if (!empty($result['success'])) {
            $this->flash('success', (string) ($result['message'] ?? 'Zaktualizowano strukture linkow permanentnych.'));
        } else {
            $this->flash('danger', (string) ($result['message'] ?? 'Nie udalo sie zaktualizowac linkow permanentnych.'));
        }

        $this->redirect("/sites/{$id}/dashboard");
    }

    public function updateRemoteService(string $id): void
    {
        Auth::requireLogin();

        $site = Site::find((int) $id);
        if (!$site) {
            $this->flash('danger', 'Strona nie znaleziona.');
            $this->redirect('/sites');
            return;
        }

        $wp = new WordPressService();
        $result = $wp->installBackproRemoteService($site);
        $status = $wp->getRemoteServiceStatus($site);

        if (!empty($result['success'])) {
            $this->flash(
                'success',
                'Zaktualizowano plik serwisowy BackPRO. Lokalna: '
                . ($status['local_version'] ?? '-')
                . ', na serwerze: '
                . ($status['remote_version'] ?? '-')
            );
        } else {
            $this->flash(
                'danger',
                (string) ($result['message'] ?? 'Nie udalo sie zaktualizowac pliku serwisowego.')
            );
        }

        $this->redirect("/sites/{$id}/dashboard");
    }

    public function installBackproNewsTheme(string $id): void
    {
        Auth::requireLogin();

        $site = Site::find((int) $id);
        if (!$site) {
            $this->flash('danger', 'Strona nie znaleziona.');
            $this->redirect('/sites');
            return;
        }

        $wp = new WordPressService();
        $result = $wp->installBackproNewsTheme($site);

        if (!empty($result['success'])) {
            $this->flash('success', (string) ($result['message'] ?? 'Zainstalowano motyw BackPRO News.'));
        } else {
            $this->flash('danger', (string) ($result['message'] ?? 'Nie udalo sie zainstalowac motywu.'));
        }

        $this->redirect("/sites/{$id}/dashboard");
    }

    public function reinstallWordPress(string $id): void
    {
        Auth::requireLogin();

        $site = Site::find((int) $id);
        if (!$site) {
            $this->json(['success' => false, 'message' => 'Strona nie znaleziona.'], 404);
            return;
        }

        $progressId = (string) $this->input('progress_id', '');
        if ($progressId === '' || !preg_match('/^[a-zA-Z0-9]{10,30}$/', $progressId)) {
            $this->json(['success' => false, 'message' => 'Nieprawidlowy identyfikator postepu.'], 422);
            return;
        }

        $republish = (bool) ((int) $this->input('republish_articles', 1));

        $installer = new InstallerService();
        $result = $installer->reinstallSite($site, $republish, $progressId);
        InstallerService::cleanupProgress($progressId);

        $this->json($result, !empty($result['success']) ? 200 : 500);
    }
}
