<?php

namespace App\Controllers\Api\V1;

use App\Controllers\BaseController;
use App\Models\CandidateProfileModel;
use App\Services\Application\ApplicationService;

class ApplicationController extends BaseController
{
    private ApplicationService $applications;

    public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
    {
        parent::initController($request, $response, $logger);
        $this->applications = new ApplicationService();
    }

    // --- Candidate: apply + view own applications ---

    public function apply(int $jobId)
    {
        $user = $this->currentUser();
        if (! $user->isCandidate()) {
            return $this->jsonError([['code' => 'FORBIDDEN', 'message' => 'Only candidates can apply to jobs.']], 403);
        }

        $profile = (new CandidateProfileModel())->findByUserId($user->id);
        $input = $this->request->getJSON(true);

        try {
            $application = $this->applications->apply(
                $profile->id,
                $jobId,
                $input['cover_note'] ?? null,
                $input['resume_id'] ?? null
            );
        } catch (\InvalidArgumentException | \RuntimeException $e) {
            return $this->jsonError([['code' => 'APPLY_FAILED', 'message' => $e->getMessage()]], 422);
        }

        return $this->jsonSuccess(['application' => $application], [], 201);
    }

    public function myApplications()
    {
        $user = $this->currentUser();
        if (! $user->isCandidate()) {
            return $this->jsonError([['code' => 'FORBIDDEN', 'message' => 'Candidate accounts only.']], 403);
        }

        $profile = (new CandidateProfileModel())->findByUserId($user->id);
        return $this->jsonSuccess(['applications' => $this->applications->candidateApplications($profile->id)]);
    }

    // --- Agency: ATS pipeline ---

    public function kanban()
    {
        $user = $this->currentUser();
        $jobId = $this->request->getGet('job_id') ? (int) $this->request->getGet('job_id') : null;

        return $this->jsonSuccess(['pipeline' => $this->applications->kanbanForAgency($user->agency_id, $jobId)]);
    }

    public function show(int $id)
    {
        try {
            $detail = $this->applications->getApplicationDetail($id);
        } catch (\RuntimeException $e) {
            return $this->jsonError([['code' => 'NOT_FOUND', 'message' => $e->getMessage()]], 404);
        }

        // "Recruiter viewed application" is its own trackable event per the
        // activity-tracking spec — logged only when an agency user (not
        // the candidate viewing their own application) opens it, and only
        // once per session-ish window isn't enforced here since repeated
        // views ARE meaningful signal (e.g. "recruiter keeps re-reading
        // this one").
        $user = $this->currentUser();
        if (! $user->isCandidate()) {
            (new \App\Services\Support\ActivityLogger())->log($user->id, $user->agency_id, $user->role_slug, 'application_viewed', ['application_id' => $id]);
        }

        return $this->jsonSuccess($detail);
    }

    /**
     * The unified "Application Timeline" — status changes, views,
     * interview events, and notes merged chronologically, plus
     * time-based analytics (time-to-first-view, time between stages,
     * total hiring time).
     */
    public function timeline(int $id)
    {
        try {
            $this->applications->getApplicationDetail($id); // reuses its existing access-control check
        } catch (\RuntimeException $e) {
            return $this->jsonError([['code' => 'NOT_FOUND', 'message' => $e->getMessage()]], 404);
        }

        $timeline = (new \App\Services\Application\ApplicationTimelineService())->build($id);
        return $this->jsonSuccess($timeline);
    }

    public function changeStatus(int $id)
    {
        $user = $this->currentUser();
        $input = $this->request->getJSON(true);

        $rules = ['status' => 'required|in_list[applied,under_review,shortlisted,interview_scheduled,interview_completed,rejected,hired]'];
        if (! $this->validate($rules)) {
            return $this->jsonValidationError($this->validator->getErrors());
        }

        try {
            $application = $this->applications->changeStatus($id, $input['status'], $user->id, $input['note'] ?? null);
        } catch (\InvalidArgumentException | \RuntimeException $e) {
            return $this->jsonError([['code' => 'STATUS_CHANGE_FAILED', 'message' => $e->getMessage()]], 422);
        }

        return $this->jsonSuccess(['application' => $application]);
    }

    public function assign(int $id)
    {
        $user = $this->currentUser();
        $input = $this->request->getJSON(true);

        if (empty($input['recruiter_id'])) {
            return $this->jsonValidationError(['recruiter_id' => 'recruiter_id is required.']);
        }

        try {
            $application = $this->applications->assignRecruiter($id, (int) $input['recruiter_id'], $user->id);
        } catch (\RuntimeException $e) {
            return $this->jsonError([['code' => 'NOT_FOUND', 'message' => $e->getMessage()]], 404);
        }

        return $this->jsonSuccess(['application' => $application]);
    }

    public function addNote(int $id)
    {
        $user = $this->currentUser();
        $input = $this->request->getJSON(true);

        if (empty($input['note'])) {
            return $this->jsonValidationError(['note' => 'Note text is required.']);
        }

        $note = $this->applications->addNote($id, $user->id, $input['note']);
        return $this->jsonSuccess(['note' => $note], [], 201);
    }
}
