<?php
declare(strict_types=1);

namespace App\Controllers;

use App\Core\{Auth, Csrf, Response, Upload};
use App\Models\{AdminLog, CommunityComment, CommunityPost};
use App\Services\Security\ZaloroxShield;
use Throwable;

class CommunityController extends BaseController
{
    private ?array $jsonPayload = null;

    public function create(): Response
    {
        if (!Auth::check()) {
            return Response::json(['ok' => false, 'message' => 'Topluluk gonderisi icin giris yapmalisin.'], 403);
        }

        if (!$this->validCsrf()) {
            return Response::json(['ok' => false, 'message' => 'Guvenlik oturumu yenilenmeli.'], 419);
        }

        $payload = $this->payload();
        $type = strtolower((string) ($payload['post_type'] ?? 'text'));
        $type = in_array($type, ['text', 'image', 'poll'], true) ? $type : 'text';
        $maxChars = (int) ($this->config['COMMUNITY_POST_MAX_CHARS'] ?? 1000);
        $content = $this->cleanMultiline((string) ($payload['content'] ?? ''), $maxChars);
        $pollQuestion = $this->cleanMultiline((string) ($payload['poll_question'] ?? ''), 240);
        $pollOptions = $this->cleanPollOptions((array) ($payload['poll_options'] ?? []));
        $errors = [];

        if ($type === 'text' && $content === '') {
            $errors['content'] = 'Metin bos olamaz.';
        }

        if ($type === 'image' && $content === '' && empty($_FILES['image']['name'])) {
            $errors['image'] = 'Resimli gonderi icin metin veya gorsel ekle.';
        }

        if ($type === 'poll') {
            if ($pollQuestion === '') {
                $errors['poll_question'] = 'Anket sorusu zorunlu.';
            }
            if (count($pollOptions) < 2) {
                $errors['poll_options'] = 'En az 2 secenek ekle.';
            }
        }

        if ($errors !== []) {
            return Response::json(['ok' => false, 'message' => 'Alanlari kontrol et.', 'errors' => $errors], 422);
        }

        try {
            $scanText = trim($content . "\n" . $pollQuestion . "\n" . implode("\n", $pollOptions));
            $scan = (new ZaloroxShield($this->config))->scanCommunityPost($scanText, Auth::id());
            if (($scan['status'] ?? 'safe') === 'blocked' || ($scan['action_taken'] ?? '') === 'blocked') {
                return Response::json([
                    'ok' => false,
                    'message' => 'Zalorox Shield bu gonderiyi engelledi.',
                    'risk_score' => (int) ($scan['risk_score'] ?? 0),
                    'errors' => ['content' => 'Icerik guvenlik kontrolunden gecemedi.'],
                ], 422);
            }

            $imagePath = null;
            if ($type === 'image' && !empty($_FILES['image']['name'])) {
                $imagePath = Upload::storeImage(
                    $_FILES['image'],
                    (string) ($this->config['COMMUNITY_IMAGE_UPLOAD_PATH'] ?? '/public/uploads/community/'),
                    (int) ($this->config['COMMUNITY_IMAGE_MAX_MB'] ?? 12)
                );
            }

            $status = (($scan['status'] ?? 'safe') === 'review' || ($scan['action_taken'] ?? '') === 'pending_review')
                ? 'pending_review'
                : 'published';

            $post = (new CommunityPost())->createPost((int) Auth::id(), $type, [
                'content' => $content,
                'poll_question' => $pollQuestion,
            ], $imagePath, $status, (int) ($scan['risk_score'] ?? 0), $pollOptions);

            return Response::json([
                'ok' => true,
                'status' => $status,
                'message' => $status === 'pending_review' ? 'Gonderi incelemeye alindi.' : 'Gonderi yayinlandi.',
                'post' => $post,
            ]);
        } catch (Throwable $exception) {
            $this->logException($exception, 'community.create');

            return Response::json(['ok' => false, 'message' => 'Topluluk gonderisi kaydedilemedi.'], 500);
        }
    }

    public function delete(): Response
    {
        if (!Auth::check()) {
            return Response::json(['ok' => false, 'message' => 'Gonderi silmek icin giris yapmalisin.'], 403);
        }

        if (!$this->validCsrf()) {
            return Response::json(['ok' => false, 'message' => 'Guvenlik oturumu yenilenmeli.'], 419);
        }

        $id = (int) ($this->payload()['id'] ?? $this->payload()['post_id'] ?? 0);
        if ($id <= 0) {
            return Response::json(['ok' => false, 'message' => 'Gonderi secimi gecersiz.'], 422);
        }

        try {
            $deleted = (new CommunityPost())->softDelete($id, (int) Auth::id(), Auth::role('admin'));

            return Response::json(['ok' => $deleted, 'message' => $deleted ? 'Gonderi silindi.' : 'Gonderi bulunamadi veya yetkin yok.'], $deleted ? 200 : 404);
        } catch (Throwable $exception) {
            $this->logException($exception, 'community.delete');

            return Response::json(['ok' => false, 'message' => 'Gonderi silinemedi.'], 500);
        }
    }

    public function react(): Response
    {
        if (!Auth::check()) {
            return Response::json(['ok' => false, 'message' => 'Reaksiyon icin giris yapmalisin.'], 403);
        }

        if (!$this->validCsrf()) {
            return Response::json(['ok' => false, 'message' => 'Guvenlik oturumu yenilenmeli.'], 419);
        }

        $payload = $this->payload();
        $postId = (int) ($payload['post_id'] ?? $payload['id'] ?? 0);
        $reaction = strtolower((string) ($payload['reaction'] ?? ''));
        if ($postId <= 0 || !in_array($reaction, ['like', 'dislike'], true)) {
            return Response::json(['ok' => false, 'message' => 'Reaksiyon gecersiz.'], 422);
        }

        try {
            $result = (new CommunityPost())->toggleReaction($postId, (int) Auth::id(), $reaction);

            return Response::json(['ok' => true] + $result);
        } catch (Throwable $exception) {
            $this->logException($exception, 'community.react');

            return Response::json(['ok' => false, 'message' => 'Reaksiyon kaydedilemedi.'], 500);
        }
    }

    public function comment(): Response
    {
        if (!Auth::check()) {
            return Response::json(['ok' => false, 'message' => 'Yorum yazmak icin giris yapmalisin.'], 403);
        }

        if (!$this->validCsrf()) {
            return Response::json(['ok' => false, 'message' => 'Guvenlik oturumu yenilenmeli.'], 419);
        }

        $payload = $this->payload();
        $postId = (int) ($payload['post_id'] ?? 0);
        $content = $this->cleanMultiline((string) ($payload['content'] ?? ''), 3000);
        $parentId = (int) ($payload['parent_id'] ?? 0);

        if ($postId <= 0 || strlen($content) < 2) {
            return Response::json(['ok' => false, 'message' => 'Yorum metni gecersiz.'], 422);
        }

        try {
            $scan = (new ZaloroxShield($this->config))->scanComment($content, Auth::id());
            $status = match ((string) ($scan['action_taken'] ?? 'allow')) {
                'blocked' => 'blocked',
                'pending_review' => 'pending_review',
                default => (($scan['status'] ?? 'safe') === 'review' ? 'pending_review' : 'published'),
            };

            if (($scan['status'] ?? 'safe') === 'blocked') {
                $status = 'blocked';
            }

            $comment = (new CommunityComment())->createForPost($postId, (int) Auth::id(), $content, $status, (int) ($scan['risk_score'] ?? 0), $parentId > 0 ? $parentId : null);

            if ($status === 'blocked') {
                return Response::json(['ok' => false, 'status' => 'blocked', 'message' => 'Zalorox Shield bu yorumu engelledi.'], 422);
            }

            return Response::json([
                'ok' => true,
                'status' => $status,
                'message' => $status === 'pending_review' ? 'Yorum incelemeye alindi.' : 'Yorum yayinlandi.',
                'comment' => $comment,
            ]);
        } catch (Throwable $exception) {
            $this->logException($exception, 'community.comment');

            return Response::json(['ok' => false, 'message' => 'Yorum kaydedilemedi.'], 500);
        }
    }

    public function pollVote(): Response
    {
        if (!Auth::check()) {
            return Response::json(['ok' => false, 'message' => 'Oy vermek icin giris yapmalisin.'], 403);
        }

        if (!$this->validCsrf()) {
            return Response::json(['ok' => false, 'message' => 'Guvenlik oturumu yenilenmeli.'], 419);
        }

        $payload = $this->payload();
        $postId = (int) ($payload['post_id'] ?? 0);
        $optionId = (int) ($payload['option_id'] ?? 0);
        if ($postId <= 0 || $optionId <= 0) {
            return Response::json(['ok' => false, 'message' => 'Anket secimi gecersiz.'], 422);
        }

        try {
            $post = (new CommunityPost())->votePoll($postId, $optionId, (int) Auth::id());

            return Response::json(['ok' => true, 'message' => 'Oy kaydedildi.', 'post' => $post]);
        } catch (\InvalidArgumentException $exception) {
            return Response::json(['ok' => false, 'message' => $exception->getMessage()], 422);
        } catch (Throwable $exception) {
            $this->logException($exception, 'community.pollVote');

            return Response::json(['ok' => false, 'message' => 'Oy kaydedilemedi.'], 500);
        }
    }

    public function zpanelList(): Response
    {
        if ($response = $this->requireAdminJson()) {
            return $response;
        }

        try {
            return Response::json(['ok' => true, 'posts' => (new CommunityPost())->listForAdmin($_GET, 200)]);
        } catch (Throwable $exception) {
            $this->logException($exception, 'zpanel.community.list');

            return Response::json(['ok' => false, 'message' => 'Topluluk gonderileri yuklenemedi.'], 500);
        }
    }

    public function zpanelApprove(): Response
    {
        return $this->zpanelSetStatus('published', 'community.approve', 'Gonderi onaylandi.');
    }

    public function zpanelBlock(): Response
    {
        return $this->zpanelSetStatus('blocked', 'community.block', 'Gonderi engellendi.');
    }

    public function zpanelDelete(): Response
    {
        return $this->zpanelSetStatus('deleted', 'community.delete', 'Gonderi silindi.');
    }

    private function zpanelSetStatus(string $status, string $action, string $message): Response
    {
        if ($response = $this->requireAdminJson()) {
            return $response;
        }

        if (!$this->validCsrf()) {
            return Response::json(['ok' => false, 'message' => 'Guvenlik oturumu yenilenmeli.'], 419);
        }

        $id = (int) ($this->payload()['id'] ?? $this->payload()['post_id'] ?? 0);
        if ($id <= 0) {
            return Response::json(['ok' => false, 'message' => 'Gonderi ID gecersiz.'], 422);
        }

        try {
            $updated = (new CommunityPost())->setStatus($id, $status);
            (new AdminLog())->write($action, 'community_post', $id, ['status' => $status]);

            return Response::json(['ok' => $updated, 'message' => $updated ? $message : 'Gonderi bulunamadi.'], $updated ? 200 : 404);
        } catch (Throwable $exception) {
            $this->logException($exception, 'zpanel.community.status');

            return Response::json(['ok' => false, 'message' => 'Gonderi guncellenemedi.'], 500);
        }
    }

    private function requireAdminJson(): ?Response
    {
        if (!Auth::check()) {
            return Response::json(['ok' => false, 'message' => 'Bu islem icin giris yapmalisin.'], 401);
        }

        if (!Auth::role('admin')) {
            return Response::json(['ok' => false, 'message' => 'Bu islem icin admin yetkisi gerekir.'], 403);
        }

        return null;
    }

    private function validCsrf(): bool
    {
        $payload = $this->payload();

        return Csrf::verify((string) ($payload['_csrf'] ?? ($_SERVER['HTTP_X_CSRF_TOKEN'] ?? '')));
    }

    private function payload(): array
    {
        if ($_POST !== []) {
            return $_POST;
        }

        if ($this->jsonPayload !== null) {
            return $this->jsonPayload;
        }

        $raw = file_get_contents('php://input') ?: '';
        $decoded = json_decode($raw, true);
        if (is_array($decoded)) {
            $this->jsonPayload = $decoded;
            return $this->jsonPayload;
        }

        parse_str($raw, $parsed);
        $this->jsonPayload = is_array($parsed) ? $parsed : [];

        return $this->jsonPayload;
    }

    private function cleanPollOptions(array $options): array
    {
        $clean = [];
        foreach ($options as $option) {
            $option = $this->cleanMultiline((string) $option, 160);
            if ($option === '' || in_array($option, $clean, true)) {
                continue;
            }
            $clean[] = $option;
            if (count($clean) >= 6) {
                break;
            }
        }

        return $clean;
    }

    private function cleanMultiline(string $value, int $limit): string
    {
        $value = trim(preg_replace("/[ \t]+/", ' ', strip_tags($value)) ?: '');
        $value = preg_replace("/\n{3,}/", "\n\n", $value) ?: '';

        return function_exists('mb_substr') ? mb_substr($value, 0, $limit) : substr($value, 0, $limit);
    }
}
