<?php

namespace App\Services\Candidate;

use App\Models\CandidateProfileModel;
use App\Models\CandidateExperienceModel;
use App\Models\CandidateEducationModel;
use App\Models\CandidateCertificationModel;
use App\Models\CandidateLanguageModel;
use App\Models\CandidateProjectModel;
use App\Models\CandidatePortfolioLinkModel;
use App\Models\CandidateReferenceModel;
use App\Models\ResumeModel;
use App\Models\SkillModel;
use App\Services\Support\ActivityLogger;
use Config\Database;

/**
 * Owns all candidate-profile business logic: creation, section CRUD,
 * profile-completion scoring, and full-profile assembly for the "me"
 * endpoint. Controllers stay thin; this is where the rules live.
 */
class CandidateProfileService
{
    private CandidateProfileModel $profileModel;
    private CandidateExperienceModel $experienceModel;
    private CandidateEducationModel $educationModel;
    private CandidateCertificationModel $certificationModel;
    private CandidateLanguageModel $languageModel;
    private CandidateProjectModel $projectModel;
    private CandidatePortfolioLinkModel $portfolioModel;
    private CandidateReferenceModel $referenceModel;
    private ResumeModel $resumeModel;
    private SkillModel $skillModel;
    private ActivityLogger $activity;

    public function __construct()
    {
        $this->profileModel       = new CandidateProfileModel();
        $this->experienceModel    = new CandidateExperienceModel();
        $this->educationModel     = new CandidateEducationModel();
        $this->certificationModel = new CandidateCertificationModel();
        $this->languageModel      = new CandidateLanguageModel();
        $this->projectModel       = new CandidateProjectModel();
        $this->portfolioModel     = new CandidatePortfolioLinkModel();
        $this->referenceModel     = new CandidateReferenceModel();
        $this->resumeModel        = new ResumeModel();
        $this->skillModel         = new SkillModel();
        $this->activity           = new ActivityLogger();
    }

    /**
     * Called right after a candidate registers (hook from AuthService).
     */
    public function createEmptyProfile(int $userId): int
    {
        return $this->profileModel->insert(['user_id' => $userId], true);
    }

    public function getFullProfile(int $userId): array
    {
        $profile = $this->profileModel->findByUserId($userId);
        if (! $profile) {
            throw new \RuntimeException("No candidate profile found for user {$userId}.");
        }

        $skills = Database::connect()->table('candidate_skills cs')
            ->select('s.id, s.name, s.category, cs.proficiency, cs.years_experience')
            ->join('skills s', 's.id = cs.skill_id')
            ->where('cs.candidate_profile_id', $profile->id)
            ->get()->getResultArray();

        return [
            'profile'        => $profile->toArray(),
            'experiences'    => $this->experienceModel->forProfile($profile->id),
            'education'      => $this->educationModel->forProfile($profile->id),
            'certifications' => $this->certificationModel->forProfile($profile->id),
            'skills'         => $skills,
            'languages'      => $this->languageModel->forProfile($profile->id),
            'projects'       => $this->projectModel->forProfile($profile->id),
            'portfolio'      => $this->portfolioModel->forProfile($profile->id),
            'references'     => $this->referenceModel->forProfile($profile->id),
            'resumes'        => $this->resumeModel->forProfile($profile->id),
        ];
    }

    public function updateBasics(int $userId, array $data): array
    {
        $profile = $this->profileModel->findByUserId($userId);
        $allowed = array_intersect_key($data, array_flip([
            'headline', 'about', 'video_intro_url', 'cover_letter',
            'salary_expectation_min', 'salary_expectation_max', 'current_salary',
            'salary_currency', 'preferred_locations', 'work_preference', 'preferred_employment_type',
            'career_level', 'industry_preferences', 'availability_status', 'notice_period_end',
            'is_public', 'hide_email', 'hide_mobile', 'hide_employer',
        ]));

        foreach (['preferred_locations', 'industry_preferences'] as $jsonField) {
            if (isset($allowed[$jsonField]) && is_array($allowed[$jsonField])) {
                $allowed[$jsonField] = json_encode($allowed[$jsonField]);
            }
        }

        $this->profileModel->update($profile->id, $allowed);
        $this->recalculateCompletion($profile->id);

        return $this->profileModel->find($profile->id)->toArray();
    }

    public function addExperience(int $candidateProfileId, array $data): array
    {
        $data['candidate_profile_id'] = $candidateProfileId;
        $id = $this->experienceModel->insert($data, true);
        $this->recalculateCompletion($candidateProfileId);
        return $this->experienceModel->find($id);
    }

    public function addEducation(int $candidateProfileId, array $data): array
    {
        $data['candidate_profile_id'] = $candidateProfileId;
        $id = $this->educationModel->insert($data, true);
        $this->recalculateCompletion($candidateProfileId);
        return $this->educationModel->find($id);
    }

    public function addSkill(int $candidateProfileId, string $skillName, string $proficiency = 'intermediate', ?int $yearsExperience = null): void
    {
        $skillId = $this->skillModel->findOrCreateByName($skillName);

        $db = Database::connect();
        $exists = $db->table('candidate_skills')
            ->where('candidate_profile_id', $candidateProfileId)
            ->where('skill_id', $skillId)
            ->get()->getRow();

        if ($exists) {
            $db->table('candidate_skills')
                ->where('candidate_profile_id', $candidateProfileId)
                ->where('skill_id', $skillId)
                ->update(['proficiency' => $proficiency, 'years_experience' => $yearsExperience]);
        } else {
            $db->table('candidate_skills')->insert([
                'candidate_profile_id' => $candidateProfileId,
                'skill_id'             => $skillId,
                'proficiency'          => $proficiency,
                'years_experience'     => $yearsExperience,
            ]);
        }

        $this->recalculateCompletion($candidateProfileId);
    }

    public function removeSkill(int $candidateProfileId, int $skillId): void
    {
        Database::connect()->table('candidate_skills')
            ->where('candidate_profile_id', $candidateProfileId)
            ->where('skill_id', $skillId)
            ->delete();

        $this->recalculateCompletion($candidateProfileId);
    }

    public function attachResume(int $candidateProfileId, string $filePath, string $originalFilename, bool $makePrimary = true): array
    {
        $id = $this->resumeModel->insert([
            'candidate_profile_id' => $candidateProfileId,
            'file_path'            => $filePath,
            'original_filename'    => $originalFilename,
            'is_primary'           => $makePrimary ? 1 : 0,
            'uploaded_at'          => date('Y-m-d H:i:s'),
        ], true);

        if ($makePrimary) {
            $this->resumeModel->unsetOtherPrimaries($candidateProfileId, $id);
        }

        $this->recalculateCompletion($candidateProfileId);
        $profile = $this->profileModel->find($candidateProfileId);
        $this->activity->log($profile->user_id ?? null, null, 'candidate', 'resume_upload', ['resume_id' => $id]);

        return $this->resumeModel->find($id);
    }

    /**
     * Weighted profile-completion score. Weights sum to 100 — each section
     * present contributes its weight. This drives the "Complete your
     * profile" UI nudge and factors into candidate search ranking (Phase 3).
     */
    public function recalculateCompletion(int $candidateProfileId): int
    {
        $profile = $this->profileModel->find($candidateProfileId);

        $weights = [
            'basics'          => 15, // headline + cover_letter
            'profile_picture' => 10,
            'experience'      => 20,
            'education'       => 15,
            'skills'          => 20,
            'resume'          => 15,
            'languages'       => 5,
        ];

        $score = 0;

        if (! empty($profile->headline) && ! empty($profile->cover_letter)) {
            $score += $weights['basics'];
        }
        if (! empty($profile->profile_picture_path)) {
            $score += $weights['profile_picture'];
        }
        if (count($this->experienceModel->forProfile($candidateProfileId)) > 0) {
            $score += $weights['experience'];
        }
        if (count($this->educationModel->forProfile($candidateProfileId)) > 0) {
            $score += $weights['education'];
        }

        $skillCount = Database::connect()->table('candidate_skills')
            ->where('candidate_profile_id', $candidateProfileId)->countAllResults();
        if ($skillCount > 0) {
            $score += $weights['skills'];
        }
        if ($this->resumeModel->primaryFor($candidateProfileId) !== null) {
            $score += $weights['resume'];
        }
        if (count($this->languageModel->forProfile($candidateProfileId)) > 0) {
            $score += $weights['languages'];
        }

        $this->profileModel->update($candidateProfileId, ['profile_completion_pct' => $score]);

        return $score;
    }

    public function touchLastActive(int $userId): void
    {
        $profile = $this->profileModel->findByUserId($userId);
        if ($profile) {
            $this->profileModel->update($profile->id, ['last_active_at' => date('Y-m-d H:i:s')]);
        }
    }
}
