import { JobService } from '../services/job.service';
import type { JobDetailInterface } from '../models/job-detail.interface';
import type { JobnetJobDetailInterface } from '../models/jobnet-job-detail.interface';

export interface JobDetailData {
  id: string;
  title: string;
  companyName: string;
  occupationName: string;
  address: string;
  description: string;
  applicationDeadline: string;
  websiteUrl: string;
  logoUrl: string;
  fromJobnet: boolean;
  isSaved: boolean;
  isApplied: boolean;
  isFullTime: boolean | null;
  workTimes: number[];
  contactName: string;
  hiringCompanyName: string;
  datePosted: string;
  employmentDate: string;
  startAsSoonAsPossible: boolean | null;
  numberOfPositions: number | null;
}

function toIsoString(value: unknown): string {
  if (value instanceof Date) {
    return value.toISOString();
  }
  if (typeof value === 'string') {
    return value;
  }
  return '';
}

function mapJobnetDetail(detail: JobnetJobDetailInterface): JobDetailData {
  const address = [detail.road, detail.houseNum, detail.zip, detail.zipName]
    .filter((part) => typeof part === 'string' && part.trim().length > 0)
    .join(' ');

  return {
    id: detail.id,
    title: detail.title ?? 'Job',
    companyName: detail.hiringCompanyName ?? 'Ukendt virksomhed',
    occupationName: detail.occupation?.name ?? '',
    address: address || detail.zipName || 'Ukendt adresse',
    description: detail.description ?? '',
    applicationDeadline: toIsoString(detail.applicationDeadline),
    websiteUrl: detail.applicationUrl || detail.hiringCompanyUrl || '',
    logoUrl: detail.logoUrl || '',
    fromJobnet: true,
    isSaved: false,
    isApplied: Boolean(detail.applied),
    isFullTime: typeof detail.isFullTime === 'boolean' ? detail.isFullTime : null,
    workTimes: Array.isArray(detail.workTimes) ? detail.workTimes : [],
    contactName: detail.contactName ?? '',
    hiringCompanyName: detail.hiringCompanyName ?? '',
    datePosted: toIsoString(detail.datePosted),
    employmentDate: toIsoString(detail.employmentDate),
    startAsSoonAsPossible: typeof detail.startAsSoonAsPossible === 'boolean' ? detail.startAsSoonAsPossible : null,
    numberOfPositions: typeof detail.numberOfPositions === 'number' ? detail.numberOfPositions : null,
  };
}

function mapArbejdDetail(id: string, detail: JobDetailInterface): JobDetailData {
  return {
    id,
    title: detail.title ?? 'Job',
    companyName: detail.companyName ?? 'Ukendt virksomhed',
    occupationName: detail.position ?? '',
    address: '',
    description: [detail.descriptionIntro, detail.descriptionPosition, detail.descriptionOffer]
      .filter((part) => typeof part === 'string' && part.trim().length > 0)
      .join('\n\n'),
    applicationDeadline: toIsoString(detail.applicationDeadline),
    websiteUrl: detail.website ?? '',
    logoUrl: '',
    fromJobnet: false,
    isSaved: false,
    isApplied: Boolean(detail.appliedJob),
    isFullTime: null,
    workTimes: Array.isArray(detail.workTimes) ? detail.workTimes : [],
    contactName: '',
    hiringCompanyName: detail.companyName ?? '',
    datePosted: '',
    employmentDate: toIsoString(detail.fromDate),
    startAsSoonAsPossible: null,
    numberOfPositions: typeof detail.numberOfPositions === 'number' ? detail.numberOfPositions : null,
  };
}

export class JobDetailViewModel {
  constructor(private jobService: JobService = new JobService()) {}

  async getDetail(jobId: string, fromJobnet: boolean): Promise<JobDetailData> {
    if (fromJobnet) {
      try {
        const detail = await this.jobService.getJobNetJobDetail(jobId);
        return mapJobnetDetail(detail);
      } catch {
        // Fallback for mixed IDs where caller/source flag is wrong.
        const legacyDetail = await this.jobService.getJobDetail(jobId);
        return mapArbejdDetail(jobId, legacyDetail);
      }
    }

    try {
      const detail = await this.jobService.getJobDetail(jobId);
      return mapArbejdDetail(jobId, detail);
    } catch {
      // Fallback for IDs that only exist in jobnet/star detail endpoint.
      const starDetail = await this.jobService.getJobNetJobDetail(jobId);
      return mapJobnetDetail(starDetail);
    }
  }

  async toggleBookmark(jobId: string, fromJobnet: boolean, save: boolean): Promise<void> {
    const jobType = fromJobnet ? 'star' : 'arbejd.com';
    await this.jobService.bookmarkJobV2(jobId, save, jobType);
  }

  async markAsApplied(jobId: string, fromJobnet: boolean): Promise<void> {
    if (fromJobnet) {
      await this.jobService.toggleApplyJobnetjob(jobId, true);
      return;
    }
    await this.jobService.applyJob(jobId);
  }
}
