import type { CandidateInterface } from '../models/candidate.interface';
import type { NotificationInterface } from '../models/notification.interface';
import type { PaymentOverview } from '../models/payment-overview.interface';
import type { JobPostingInterface } from '../models/job.interface';
import { CandidateService } from '../services/candidate.service';
import { JobService } from '../services/job.service';
import { NotificationService } from '../services/notification.service';
import { SimulationService } from '../services/simulation.service';
import { SubscriptionService } from '../services/subscription.service';
import { MessagesViewModel, type MessageThreadItem } from './MessagesViewModel';

export interface DashboardBestJobItem {
  id: string;
  title: string;
  companyName: string;
  address: string;
  applicationDeadline: string;
  candidateDistance: number | null;
  fromJobnet: boolean;
  logoUrl: string;
  companyLogoImage: string;
}

export interface DashboardEvaluationItem {
  id: string;
  jobName: string;
  companyName: string | null;
  interviewDate: string | null;
  recommendation: string | null;
  isCompleted: boolean;
}

export interface DashboardInitialData {
  candidate: CandidateInterface | null;
  notifications: NotificationInterface[];
  messages: MessageThreadItem[];
  bestJobs: DashboardBestJobItem[];
  subscription: PaymentOverview | null;
  evaluations: DashboardEvaluationItem[];
}

function asRecord(value: unknown): Record<string, unknown> | null {
  return typeof value === 'object' && value !== null ? (value as Record<string, unknown>) : null;
}

function normalizeText(value: unknown): string {
  return typeof value === 'string' ? value : '';
}

function toNullableNumber(value: unknown): number | null {
  return typeof value === 'number' ? value : null;
}

function toBestJobItem(value: unknown): DashboardBestJobItem | null {
  const source = asRecord(value);
  if (!source) {
    return null;
  }

  const postingSource = asRecord(source.jobPosting);
  const posting = postingSource ?? source;

  const id = normalizeText(posting.id);
  if (!id) {
    return null;
  }

  return {
    id,
    title: normalizeText(posting.title),
    companyName: normalizeText(posting.companyName),
    address: normalizeText(posting.address),
    applicationDeadline: normalizeText(posting.applicationDeadline),
    candidateDistance: toNullableNumber(posting.candidateDistance),
    fromJobnet: Boolean(posting.fromJobnet),
    logoUrl: normalizeText(posting.logoUrl),
    companyLogoImage: normalizeText(posting.companyLogoImage),
  };
}

function toEvaluationItems(value: unknown): DashboardEvaluationItem[] {
  const root = asRecord(value);
  const interviews = Array.isArray(root?.interviews) ? root.interviews : [];

  return interviews
    .map((item) => {
      const source = asRecord(item);
      if (!source) {
        return null;
      }
      const id = normalizeText(source.id);
      if (!id) {
        return null;
      }

      return {
        id,
        jobName: normalizeText(source.job_name) || 'Interview',
        companyName: normalizeText(source.company_name) || null,
        interviewDate: normalizeText(source.interview_date) || null,
        recommendation: normalizeText(source.recommendation) || null,
        isCompleted: Boolean(source.is_completed),
      } satisfies DashboardEvaluationItem;
    })
    .filter((item): item is DashboardEvaluationItem => Boolean(item))
    .sort((a, b) => {
      const aTime = a.interviewDate ? new Date(a.interviewDate).getTime() : 0;
      const bTime = b.interviewDate ? new Date(b.interviewDate).getTime() : 0;
      return bTime - aTime;
    })
    .slice(0, 5);
}

function extractSearchList(payload: unknown): unknown[] {
  const root = asRecord(payload);
  if (!root) {
    return [];
  }
  return Array.isArray(root.searchList) ? root.searchList : [];
}

export class DashboardViewModel {
  constructor(
    private readonly candidateService: CandidateService = new CandidateService(),
    private readonly notificationService: NotificationService = new NotificationService(),
    private readonly jobService: JobService = new JobService(),
    private readonly subscriptionService: SubscriptionService = new SubscriptionService(),
    private readonly simulationService: SimulationService = new SimulationService(),
    private readonly messagesViewModel: MessagesViewModel = new MessagesViewModel(),
  ) {}

  async loadInitialData(): Promise<DashboardInitialData> {
    const [candidateResult, notificationsResult, messagesResult, bestJobsResult, subscriptionResult, evaluationsResult] =
      await Promise.allSettled([
        this.candidateService.getCandidate(),
        this.notificationService.getNotifications(0, 5),
        this.messagesViewModel.getThreads(),
        this.loadBestJobs(),
        this.subscriptionService.getPaymentOverview(),
        this.simulationService.listInterviews(5, 0),
      ]);

    return {
      candidate: candidateResult.status === 'fulfilled' ? candidateResult.value : null,
      notifications: notificationsResult.status === 'fulfilled' ? notificationsResult.value.slice(0, 5) : [],
      messages: messagesResult.status === 'fulfilled' ? messagesResult.value.slice(0, 5) : [],
      bestJobs: bestJobsResult.status === 'fulfilled' ? bestJobsResult.value : [],
      subscription: subscriptionResult.status === 'fulfilled' ? subscriptionResult.value : null,
      evaluations: evaluationsResult.status === 'fulfilled' ? toEvaluationItems(evaluationsResult.value) : [],
    };
  }

  private async loadBestJobs(): Promise<DashboardBestJobItem[]> {
    const payload = await this.jobService.getJobsV2(10, 0, 5, []);
    const list = extractSearchList(payload);
    return list
      .map((item) => toBestJobItem(item))
      .filter((item): item is DashboardBestJobItem => Boolean(item))
      .slice(0, 5);
  }
}

