<?php

namespace App\Controllers;

use App\Models\UserModel;
use App\Models\CandidateProfileModel;
use App\Models\AgencyModel;
use App\Services\Candidate\CandidateProfileService;
use App\Services\PublicProfile\ContactViewLimitService;
use App\Services\Seo\SeoService;
use Config\Database;

class PublicProfileController extends BaseController
{
    public function show(string $username)
    {
        $userModel = new UserModel();
        $user = $userModel->select('users.*, roles.slug as role_slug')
            ->join('roles', 'roles.id = users.role_id')
            ->where('users.username', strtolower($username))
            ->where('users.status', 'active')
            ->first();

        if (! $user) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }

        $this->recordProfileView($user->id);

        if ($user->role_slug === 'candidate') {
            return $this->showCandidate($user);
        }

        if ($user->role_slug === 'agency_owner') {
            return $this->showAgency($user);
        }

        throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
    }

    /**
     * Logs a profile view for the "Who Viewed My Profile" feature —
     * only for logged-in viewers (anonymous traffic isn't attributable to
     * anyone), and never counts a self-view. One row per visit; the
     * candidate-facing summary groups these by viewer and shows the most
     * recent visit, so repeat views don't need de-duplicating here.
     */
    private function recordProfileView(int $viewedUserId): void
    {
        $viewerId = session()->get('user_id');
        if (! $viewerId || (int) $viewerId === $viewedUserId) {
            return;
        }

        Database::connect()->table('profile_views')->insert([
            'viewer_user_id' => $viewerId,
            'viewed_user_id' => $viewedUserId,
            'created_at'     => date('Y-m-d H:i:s'),
        ]);
    }

    private function showCandidate($user)
    {
        $profileModel = new CandidateProfileModel();
        $profile = $profileModel->findByUserId($user->id);
        if (! $profile || ! $profile->is_public) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }

        $service = new CandidateProfileService();
        $full = $service->getFullProfile($user->id);

        $viewerLoggedIn = (bool) session()->get('user_id');

        $meta = [
            'title'       => ($profile->headline ? "{$user->name} — {$profile->headline}" : $user->name) . ' | Job Portal',
            'description' => $profile->about ? mb_substr(strip_tags($profile->about), 0, 160) : "View {$user->name}'s professional profile on Job Portal.",
        ];

        return view('public/candidate_profile', [
            'title'          => $meta['title'],
            'metaDescription'=> $meta['description'],
            'user'           => $user,
            'profile'        => $profile,
            'experiences'    => $full['experiences'],
            'education'      => $full['education'],
            'certifications' => $full['certifications'],
            'skills'         => $full['skills'],
            'languages'      => $full['languages'],
            'projects'       => $full['projects'],
            'portfolio'      => $full['portfolio'],
            'viewerLoggedIn' => $viewerLoggedIn,
            'viewerId'       => session()->get('user_id'),
            'jsonLd'         => $this->candidateJsonLd($user, $profile, $full),
        ]);
    }

    private function showAgency($user)
    {
        $agencyModel = new AgencyModel();
        $agency = $agencyModel->find($user->agency_id);
        if (! $agency || ! $agency->isActive()) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }

        $db = Database::connect();
        $activeJobs = $db->table('jobs')->where('agency_id', $agency->id)->where('status', 'published')->orderBy('created_at', 'DESC')->limit(10)->get()->getResultArray();
        $jobCount = $db->table('jobs')->where('agency_id', $agency->id)->where('status', 'published')->countAllResults();
        $reviews = $db->table('company_reviews')->where('agency_id', $agency->id)->where('status', 'approved')->orderBy('created_at', 'DESC')->limit(10)->get()->getResultArray();
        $avgRating = $db->table('company_reviews')->selectAvg('rating')->where('agency_id', $agency->id)->where('status', 'approved')->get()->getRow()->rating ?? null;

        $viewerLoggedIn = (bool) session()->get('user_id');

        $socialLinks = $agency->social_links ?: [];

        return view('public/agency_profile', [
            'title'           => $agency->company_name . ' | Job Portal',
            'metaDescription' => $agency->description ? mb_substr(strip_tags($agency->description), 0, 160) : "View {$agency->company_name}'s company profile and open positions.",
            'user'            => $user,
            'agency'          => $agency,
            'socialLinks'     => $socialLinks,
            'activeJobs'      => $activeJobs,
            'jobCount'        => $jobCount,
            'reviews'         => $reviews,
            'avgRating'       => $avgRating !== null ? round((float) $avgRating, 1) : null,
            'viewerLoggedIn'  => $viewerLoggedIn,
            'viewerId'        => session()->get('user_id'),
            'jsonLd'          => $this->agencyJsonLd($agency, $user->username),
        ]);
    }

    /**
     * AJAX endpoint the "Reveal Contact" / "Contact via Email" buttons call.
     * Requires login (candidate or agency account per spec), enforces the
     * daily view limit, and returns the raw value only in this JSON
     * response — never rendered as static page text, per the anti-scraping
     * requirement.
     */
    public function revealContact(string $username)
    {
        if (! session()->get('user_id')) {
            return $this->jsonError([['code' => 'LOGIN_REQUIRED', 'message' => 'Please log in as a Candidate or Agency to view contact details.']], 401);
        }

        $userModel = new UserModel();
        $targetUser = $userModel->where('username', strtolower($username))->first();
        if (! $targetUser) {
            return $this->jsonError([['code' => 'NOT_FOUND', 'message' => 'Profile not found.']], 404);
        }

        $limiter = new ContactViewLimitService();
        try {
            $limiter->checkAndRecord((int) session()->get('user_id'));
        } catch (\App\Exceptions\ContactViewLimitExceededException $e) {
            return $this->jsonError([[
                'code' => 'DAILY_LIMIT_REACHED',
                'message' => $e->getMessage(),
                'seconds_until_reset' => $e->secondsUntilReset,
            ]], 429);
        }

        (new \App\Services\Support\ActivityLogger())->log(
            (int) session()->get('user_id'), null, session()->get('role'), 'contact_reveal_public_profile', ['target_user_id' => $targetUser->id]
        );

        return $this->jsonSuccess([
            'email' => $targetUser->email,
            'phone' => $targetUser->phone,
        ]);
    }

    private function candidateJsonLd($user, $profile, array $full): string
    {
        $schema = [
            '@context' => 'https://schema.org',
            '@type'    => 'Person',
            'name'     => $user->name,
            'jobTitle' => $profile->headline,
            'description' => $profile->about,
            'url'      => base_url('profile/' . $user->username),
        ];

        if (! empty($full['skills'])) {
            $schema['knowsAbout'] = array_column($full['skills'], 'name');
        }

        return json_encode(array_filter($schema, fn ($v) => $v !== null), JSON_UNESCAPED_SLASHES);
    }

    private function agencyJsonLd($agency, string $username): string
    {
        $schema = [
            '@context'    => 'https://schema.org',
            '@type'       => 'Organization',
            'name'        => $agency->company_name,
            'description' => $agency->description,
            'url'         => base_url('profile/' . $username),
            'logo'        => $agency->logo_path ? base_url($agency->logo_path) : null,
            'sameAs'      => $agency->website,
        ];

        return json_encode(array_filter($schema, fn ($v) => $v !== null), JSON_UNESCAPED_SLASHES);
    }
}
