<?php

namespace App\Services\Application;

use Config\Database;

/**
 * Builds the unified "Application Timeline" — every status change,
 * recruiter view, interview event, and note on one application, merged
 * into a single chronological list (not just the raw status_history
 * table), plus the time-based analytics called for in the activity
 * tracking spec: time-to-first-view, time-between-stages, total hiring
 * time. Nothing here deletes or overwrites history — every entry is an
 * additive row from its source table.
 */
class ApplicationTimelineService
{
    public function build(int $applicationId): array
    {
        $db = Database::connect();
        $events = [];

        $application = $db->table('job_applications')->where('id', $applicationId)->get()->getRowArray();
        if ($application) {
            $events[] = [
                'type'      => 'submitted',
                'label'     => 'Application Submitted',
                'timestamp' => $application['applied_at'],
                'actor'     => null,
                'note'      => null,
            ];
        }

        $statusChanges = $db->table('application_status_history ash')
            ->select('ash.from_status, ash.to_status, ash.note, ash.created_at, u.name as actor_name, r.slug as actor_role')
            ->join('users u', 'u.id = ash.changed_by_user_id')
            ->join('roles r', 'r.id = u.role_id')
            ->where('ash.job_application_id', $applicationId)
            ->orderBy('ash.created_at', 'ASC')
            ->get()->getResultArray();

        foreach ($statusChanges as $change) {
            $events[] = [
                'type'      => 'status_change',
                'label'     => $this->statusLabel($change['to_status']),
                'from_status' => $change['from_status'],
                'to_status' => $change['to_status'],
                'timestamp' => $change['created_at'],
                'actor'     => $change['actor_name'],
                'actor_role' => $change['actor_role'],
                'note'      => $change['note'],
            ];
        }

        $views = $db->table('activity_logs al')
            ->select('al.created_at, u.name as actor_name, r.slug as actor_role')
            ->join('users u', 'u.id = al.user_id')
            ->join('roles r', 'r.id = u.role_id')
            ->where('al.action', 'application_viewed')
            ->like('al.metadata', '"application_id":' . (int) $applicationId)
            ->orderBy('al.created_at', 'ASC')
            ->get()->getResultArray();

        foreach ($views as $view) {
            $events[] = [
                'type'      => 'viewed',
                'label'     => 'Application Viewed',
                'timestamp' => $view['created_at'],
                'actor'     => $view['actor_name'],
                'actor_role' => $view['actor_role'],
                'note'      => null,
            ];
        }

        $interviews = $db->table('interviews i')
            ->select('i.id, i.status, i.scheduled_at, i.mode, i.created_at, i.updated_at, i.feedback, i.feedback_rating')
            ->where('i.job_application_id', $applicationId)
            ->orderBy('i.created_at', 'ASC')
            ->get()->getResultArray();

        foreach ($interviews as $interview) {
            $events[] = [
                'type'      => 'interview',
                'label'     => 'Interview Scheduled (' . str_replace('_', ' ', $interview['mode']) . ')',
                'timestamp' => $interview['created_at'],
                'actor'     => null,
                'note'      => 'Scheduled for ' . $interview['scheduled_at'],
            ];
            if ($interview['status'] === 'completed' && $interview['feedback']) {
                $events[] = [
                    'type'      => 'interview_feedback',
                    'label'     => 'Interview Feedback Added',
                    'timestamp' => $interview['updated_at'],
                    'actor'     => null,
                    'note'      => $interview['feedback_rating'] ? "Rating: {$interview['feedback_rating']}/5" : null,
                ];
            }
            if ($interview['status'] === 'cancelled') {
                $events[] = [
                    'type'      => 'interview_cancelled',
                    'label'     => 'Interview Cancelled',
                    'timestamp' => $interview['updated_at'],
                    'actor'     => null,
                    'note'      => null,
                ];
            }
        }

        $notes = $db->table('application_notes an')
            ->select('an.note, an.created_at, u.name as actor_name')
            ->join('users u', 'u.id = an.author_user_id', 'left')
            ->where('an.job_application_id', $applicationId)
            ->orderBy('an.created_at', 'ASC')
            ->get()->getResultArray();

        foreach ($notes as $note) {
            $events[] = [
                'type'      => 'note',
                'label'     => 'Note Added',
                'timestamp' => $note['created_at'],
                'actor'     => $note['actor_name'],
                'note'      => $note['note'],
            ];
        }

        usort($events, fn ($a, $b) => strtotime((string) $a['timestamp']) <=> strtotime((string) $b['timestamp']));

        return [
            'events'    => $events,
            'analytics' => $this->computeAnalytics($events),
        ];
    }

    private function computeAnalytics(array $events): array
    {
        $submitted = null;
        $firstView = null;
        $stageTimestamps = [];
        $terminal = null;

        foreach ($events as $event) {
            $ts = strtotime((string) $event['timestamp']);
            if (! $ts) {
                continue;
            }
            if ($event['type'] === 'submitted') {
                $submitted = $ts;
            }
            if ($event['type'] === 'viewed' && $firstView === null) {
                $firstView = $ts;
            }
            if ($event['type'] === 'status_change') {
                $stageTimestamps[$event['to_status']] = $ts;
                if (in_array($event['to_status'], ['hired', 'rejected'], true)) {
                    $terminal = ['status' => $event['to_status'], 'timestamp' => $ts];
                }
            }
        }

        $analytics = [];
        if ($submitted && $firstView) {
            $analytics['time_to_first_view'] = $this->humanDuration($firstView - $submitted);
        }

        $stageOrder = ['applied', 'under_review', 'shortlisted', 'interview_scheduled', 'interview_completed', 'hired'];
        $priorTs = $submitted;
        $priorLabel = 'Submitted';
        foreach ($stageOrder as $stage) {
            if (isset($stageTimestamps[$stage]) && $priorTs) {
                $analytics['stage_durations'][] = [
                    'from'     => $priorLabel,
                    'to'       => $this->statusLabel($stage),
                    'duration' => $this->humanDuration($stageTimestamps[$stage] - $priorTs),
                ];
                $priorTs = $stageTimestamps[$stage];
                $priorLabel = $this->statusLabel($stage);
            }
        }

        if ($submitted && $terminal) {
            $analytics['total_time'] = $this->humanDuration($terminal['timestamp'] - $submitted);
            $analytics['outcome'] = $terminal['status'];
        }

        return $analytics;
    }

    private function humanDuration(int $seconds): string
    {
        if ($seconds < 0) {
            return '0 minutes';
        }
        $days = intdiv($seconds, 86400);
        $hours = intdiv($seconds % 86400, 3600);
        $minutes = intdiv($seconds % 3600, 60);

        $parts = [];
        if ($days > 0) {
            $parts[] = "{$days} day" . ($days === 1 ? '' : 's');
        }
        if ($hours > 0) {
            $parts[] = "{$hours} hour" . ($hours === 1 ? '' : 's');
        }
        if ($minutes > 0 && $days === 0) {
            $parts[] = "{$minutes} minute" . ($minutes === 1 ? '' : 's');
        }

        return $parts ? implode(' ', $parts) : 'less than a minute';
    }

    private function statusLabel(string $status): string
    {
        $map = [
            'applied'              => 'Applied',
            'under_review'         => 'Viewed',
            'shortlisted'          => 'Shortlisted',
            'interview_scheduled'  => 'Interview Scheduled',
            'interview_completed'  => 'Interview Completed',
            'hired'                => 'Selected',
            'rejected'             => 'Rejected',
        ];
        return $map[$status] ?? ucwords(str_replace('_', ' ', $status));
    }
}
