<?php
declare(strict_types=1);

namespace App\Controllers;

use App\Core\{Auth, Csrf, Response};
use App\Models\{CommunityPost, Friendship, Mod, Music, Package, Profile, Story, User};
use Throwable;

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

    public function show(string $nickname): string
    {
        $nickname = $this->safeNickname($nickname);
        if ($nickname === null) {
            return $this->notFoundProfile();
        }

        try {
            $profileModel = new Profile();
            $profile = $profileModel->findPublicByNickname($nickname);

            if (!$profile) {
                return $this->notFoundProfile();
            }

            $viewerId = Auth::id();
            $isAdmin = Auth::role('admin');
            $isOwnProfile = $viewerId !== null && $viewerId === (int) $profile['id'];
            $friendshipModel = new Friendship();
            $relationship = $viewerId
                ? $friendshipModel->relationship($viewerId, (int) $profile['id'])
                : ['state' => 'guest', 'friendship' => null];

            $visibility = $this->visibility($profile, $viewerId, $isAdmin);
            $stats = $this->emptyStats();
            try {
                $stats = $profileModel->statsForUser((int) $profile['id']);
            } catch (Throwable $exception) {
                $this->logException($exception, 'profile.stats.inline');
            }
            $socialLinks = $profileModel->publicSocialLinks($profile);
            $isFollowing = $viewerId ? $profileModel->isFollowing($viewerId, (int) $profile['id']) : false;

            if (!$visibility['allowed']) {
                return $this->view('main', 'profile/show', [
                    'title' => '@' . ($profile['nickname'] ?? $nickname),
                    'profile' => $profile,
                    'nickname' => $nickname,
                    'relationship' => $relationship,
                    'stats' => $stats,
                    'socialLinks' => [],
                    'mods' => [],
                    'musicTracks' => [],
                    'communityPosts' => [],
                    'activeStory' => null,
                    'packages' => [],
                    'accessDenied' => true,
                    'accessReason' => $visibility['reason'],
                    'canMessage' => false,
                    'messagePermission' => ['allowed' => false, 'reason' => 'Profil gizli.'],
                    'isFollowing' => $isFollowing,
                    'viewerHasActiveSubscription' => false,
                ]);
            }

            $packages = [];
            $viewerHasActiveSubscription = false;
            try {
                $packages = (new Package())->activeForCreator((int) $profile['id']);
                foreach ($packages as &$package) {
                    $package['viewer_is_subscribed'] = $viewerId
                        ? Auth::hasActiveSubscription((int) $viewerId, (int) $profile['id'], (int) $package['id'])
                        : false;
                    $viewerHasActiveSubscription = $viewerHasActiveSubscription || (bool) $package['viewer_is_subscribed'];
                }
                unset($package);
                if ($viewerId && !$viewerHasActiveSubscription) {
                    $viewerHasActiveSubscription = Auth::hasActiveSubscription((int) $viewerId, (int) $profile['id']);
                }
            } catch (Throwable $exception) {
                $this->logException($exception, 'profile.packages');
            }

            $mods = [];
            $musicTracks = [];
            $communityPosts = [];
            $activeStory = null;
            try {
                $mods = (new Mod())->publishedForCreator((int) $profile['id'], 24);
                $musicTracks = (new Music())->publishedForCreator((int) $profile['id'], 24);
            } catch (Throwable $exception) {
                $this->logException($exception, 'profile.content');
            }
            try {
                $communityPosts = (new CommunityPost())->listForUser((int) $profile['id'], Auth::id(), 24);
                $activeStory = (new Story())->activeForUser((int) $profile['id'], Auth::id());
            } catch (Throwable $exception) {
                $this->logException($exception, 'profile.community-story');
            }

            $messagePermission = $this->messagePermission($profile, $viewerId, $relationship, $friendshipModel);

            return $this->view('main', 'profile/show', [
                'title' => '@' . ($profile['username'] ?? $nickname),
                'profile' => $profile,
                'nickname' => $nickname,
                'relationship' => $relationship,
                'stats' => $stats,
                'socialLinks' => $socialLinks,
                'mods' => $mods,
                'musicTracks' => $musicTracks,
                'communityPosts' => $communityPosts,
                'activeStory' => $activeStory,
                'packages' => $packages,
                'accessDenied' => false,
                'accessReason' => '',
                'canMessage' => $messagePermission['allowed'],
                'messagePermission' => $messagePermission,
                'isFollowing' => $isFollowing,
                'viewerHasActiveSubscription' => $viewerHasActiveSubscription,
                'isOwnProfile' => $isOwnProfile,
            ]);
        } catch (Throwable $exception) {
            $this->logException($exception, 'profile.show');

            return $this->view('main', 'profile/show', [
                'title' => '@' . $nickname,
                'profile' => null,
                'nickname' => $nickname,
                'relationship' => ['state' => 'guest', 'friendship' => null],
                'stats' => $this->emptyStats(),
                'socialLinks' => [],
                'mods' => [],
                'musicTracks' => [],
                'communityPosts' => [],
                'activeStory' => null,
                'packages' => [],
                'accessDenied' => true,
                'accessReason' => 'Profil su anda yuklenemedi.',
                'canMessage' => false,
                'messagePermission' => ['allowed' => false, 'reason' => 'Profil yuklenemedi.'],
                'isFollowing' => false,
                'viewerHasActiveSubscription' => false,
            ]);
        }
    }

    public function follow(): Response
    {
        return $this->followToggle(true);
    }

    public function unfollow(): Response
    {
        return $this->followToggle(false);
    }

    public function stats(string $nickname): Response
    {
        $nickname = $this->safeNickname($nickname);
        if ($nickname === null) {
            return Response::json(['ok' => false, 'message' => 'Profil bulunamadi.'], 404);
        }

        try {
            $profileModel = new Profile();
            $profile = $profileModel->findPublicByNickname($nickname);
            if (!$profile) {
                return Response::json(['ok' => false, 'message' => 'Profil bulunamadi.'], 404);
            }

            $visibility = $this->visibility($profile, Auth::id(), Auth::role('admin'));
            if (!$visibility['allowed']) {
                return Response::json(['ok' => false, 'message' => $visibility['reason']], 403);
            }

            return Response::json([
                'ok' => true,
                'user_id' => (int) $profile['id'],
                'stats' => $profileModel->statsForUser((int) $profile['id']),
            ]);
        } catch (Throwable $exception) {
            $this->logException($exception, 'profile.stats');

            return Response::json(['ok' => false, 'message' => 'Profil istatistikleri su anda yuklenemedi.'], 500);
        }
    }

    private function followToggle(bool $follow): Response
    {
        $viewerId = Auth::id();
        if (!$viewerId) {
            return Response::json(['ok' => false, 'message' => 'Takip etmek icin giris yapmalisin.'], 403);
        }

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

        $targetId = (int) ($this->payload()['user_id'] ?? $this->payload()['followed_id'] ?? 0);
        if ($targetId <= 0 || $targetId === $viewerId) {
            return Response::json(['ok' => false, 'message' => 'Takip hedefi gecersiz.'], 422);
        }

        try {
            $target = (new User())->findPublicById($targetId);
            if (!$target) {
                return Response::json(['ok' => false, 'message' => 'Kullanici bulunamadi.'], 404);
            }

            if ((new Friendship())->isBlockedBetween($viewerId, $targetId)) {
                return Response::json(['ok' => false, 'message' => 'Bu kullanici ile etkilesim engellenmis.'], 403);
            }

            $profileModel = new Profile();
            if ($follow) {
                $profileModel->follow($viewerId, $targetId);
            } else {
                $profileModel->unfollow($viewerId, $targetId);
            }

            return Response::json([
                'ok' => true,
                'following' => $follow,
                'follower_count' => $profileModel->followerCount($targetId),
                'message' => $follow ? 'Takip ediliyor.' : 'Takip birakildi.',
            ]);
        } catch (Throwable $exception) {
            $this->logException($exception, $follow ? 'profile.follow' : 'profile.unfollow');

            return Response::json(['ok' => false, 'message' => 'Takip islemi su anda tamamlanamadi.'], 500);
        }
    }

    private function visibility(array $profile, ?int $viewerId, bool $isAdmin): array
    {
        $ownerId = (int) ($profile['id'] ?? 0);
        $privacy = (string) (($profile['privacy'] ?? '') ?: 'public');

        if ($privacy === 'public') {
            return ['allowed' => true, 'reason' => ''];
        }

        if ($privacy === 'logged_in') {
            return $viewerId
                ? ['allowed' => true, 'reason' => '']
                : ['allowed' => false, 'reason' => 'Bu profili gormek icin giris yapmalisin.'];
        }

        if ($privacy === 'private' && ($isAdmin || ($viewerId !== null && $viewerId === $ownerId))) {
            return ['allowed' => true, 'reason' => ''];
        }

        return ['allowed' => false, 'reason' => 'Bu profil sahibi tarafindan gizli tutuluyor.'];
    }

    private function messagePermission(array $profile, ?int $viewerId, array $relationship, Friendship $friendshipModel): array
    {
        $ownerId = (int) ($profile['id'] ?? 0);
        if (!$viewerId) {
            return ['allowed' => false, 'reason' => 'Mesaj gondermek icin giris yapmalisin.'];
        }

        if ($viewerId === $ownerId) {
            return ['allowed' => false, 'reason' => 'Kendi profiline mesaj gonderemezsin.'];
        }

        if ($friendshipModel->isBlockedBetween($viewerId, $ownerId)) {
            return ['allowed' => false, 'reason' => 'Bu kullanici ile mesajlasamazsin.'];
        }

        if (Auth::role('admin')) {
            return ['allowed' => true, 'reason' => ''];
        }

        $messagePrivacy = (string) (($profile['message_privacy'] ?? '') ?: 'everyone');
        if ($messagePrivacy === 'everyone') {
            return ['allowed' => true, 'reason' => ''];
        }

        if ($messagePrivacy === 'friends') {
            return ($relationship['state'] ?? '') === 'friends'
                ? ['allowed' => true, 'reason' => '']
                : ['allowed' => false, 'reason' => 'Bu kullanici sadece arkadaslarindan mesaj kabul ediyor.'];
        }

        return ['allowed' => false, 'reason' => 'Bu kullanici mesaj alimini kapatmis.'];
    }

    private function safeNickname(string $nickname): ?string
    {
        $nickname = rawurldecode($nickname);
        $nickname = strtolower(trim($nickname));

        if ($nickname === '' || strlen($nickname) > 120) {
            return null;
        }

        if (!preg_match('~^[a-z0-9._-]+$~', $nickname)) {
            return null;
        }

        return $nickname;
    }

    private function notFoundProfile(): string
    {
        http_response_code(404);

        return $this->view('main', 'pages/show', [
            'title' => 'Profil bulunamadi',
            'page' => [
                'title' => 'Profil bulunamadi',
                'content' => 'Bu kullanici yayinda degil veya silinmis.',
            ],
        ]);
    }

    private function emptyStats(): array
    {
        return [
            'mod_count' => 0,
            'music_count' => 0,
            'total_downloads' => 0,
            'total_plays' => 0,
            'total_views' => 0,
            'subscriber_count' => 0,
            'follower_count' => 0,
            'following_count' => 0,
        ];
    }

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

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

        $decoded = json_decode(file_get_contents('php://input') ?: '', true);
        $this->jsonPayload = is_array($decoded) ? $decoded : [];

        return $this->jsonPayload;
    }
}
