import { ApiClientError, apiClient } from '@/lib/api-client';
import type {
  BootstrapSetupStatusResponse,
  CompleteBootstrapSetupPayload,
  CsvPreviewResult,
  ImportReport,
  SaveSetupStepPayload,
  SetupProfilesResponse,
  SetupReadinessReport,
  SetupRunResponse,
  SetupTemplatesResponse,
  SetupVerificationPayload,
  SetupVerificationReport
} from './types';

interface ApiErrorPayload {
  message?: string;
  error?: string;
}

function withProfile(endpoint: string, profileId?: string) {
  if (!profileId) return endpoint;
  const separator = endpoint.includes('?') ? '&' : '?';
  return `${endpoint}${separator}profile=${encodeURIComponent(profileId)}`;
}

async function readUploadResponse<T>(response: Response): Promise<T> {
  if (response.ok) {
    return response.json() as Promise<T>;
  }

  const payload = (await response.json().catch(() => null)) as ApiErrorPayload | null;
  const message = payload?.message ?? payload?.error ?? `API error: ${response.status}`;

  throw new ApiClientError(message, {
    status: response.status,
    statusText: response.statusText,
    payload
  });
}

function buildCsvFormData(files: File[]): FormData {
  const formData = new FormData();
  files.forEach((file) => formData.append('files', file, file.name));
  return formData;
}

function bootstrapHeaders(bootstrapToken?: string) {
  return bootstrapToken ? { 'x-bootstrap-setup-token': bootstrapToken } : undefined;
}

export async function getSetupReadiness(profileId?: string): Promise<SetupReadinessReport> {
  return apiClient<SetupReadinessReport>(withProfile('/setup/readiness', profileId));
}

export async function getSetupTemplates(profileId?: string): Promise<SetupTemplatesResponse> {
  return apiClient<SetupTemplatesResponse>(withProfile('/setup/templates', profileId));
}

export async function getSetupProfiles(profileId?: string): Promise<SetupProfilesResponse> {
  return apiClient<SetupProfilesResponse>(withProfile('/setup/profiles', profileId));
}

export async function getBootstrapSetupStatus(): Promise<BootstrapSetupStatusResponse> {
  return apiClient<BootstrapSetupStatusResponse>('/setup/bootstrap/status');
}

export async function getCurrentSetupRun(): Promise<SetupRunResponse> {
  return apiClient<SetupRunResponse>('/setup/run/current');
}

export async function getCurrentBootstrapSetupRun(bootstrapToken?: string): Promise<SetupRunResponse> {
  return readUploadResponse<SetupRunResponse>(
    await fetch('/api/setup/bootstrap/run/current', {
      headers: bootstrapHeaders(bootstrapToken)
    })
  );
}

export async function startSetupRun(): Promise<SetupRunResponse> {
  return apiClient<SetupRunResponse>('/setup/run/start', {
    method: 'POST',
    body: JSON.stringify({ mode: 'production' })
  });
}

export async function saveSetupStep(payload: SaveSetupStepPayload): Promise<SetupRunResponse> {
  return apiClient<SetupRunResponse>('/setup/run/steps', {
    method: 'POST',
    body: JSON.stringify(payload)
  });
}

export async function getSetupRunReport(): Promise<SetupRunResponse> {
  return apiClient<SetupRunResponse>('/setup/run/report');
}

export async function completeSetupRun(report: Record<string, unknown>): Promise<SetupRunResponse> {
  return apiClient<SetupRunResponse>('/setup/run/complete', {
    method: 'POST',
    body: JSON.stringify({ report })
  });
}

export async function verifySetup(payload: SetupVerificationPayload): Promise<SetupVerificationReport> {
  return apiClient<SetupVerificationReport>('/setup/verify', {
    method: 'POST',
    body: JSON.stringify(payload)
  });
}

export async function previewSetupCsvFiles(files: File[]): Promise<CsvPreviewResult> {
  return readUploadResponse<CsvPreviewResult>(
    await fetch('/api/setup/import/preview', {
      method: 'POST',
      body: buildCsvFormData(files)
    })
  );
}

export async function previewConfiguredSetupCsvFiles(): Promise<CsvPreviewResult> {
  return readUploadResponse<CsvPreviewResult>(
    await fetch('/api/setup/import/preview', {
      method: 'POST',
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify({ source: 'configured-directory' })
    })
  );
}

export async function previewBootstrapCsvStep(input: {
  stepKey: string;
  file: File;
  bootstrapToken?: string;
}): Promise<CsvPreviewResult> {
  const formData = buildCsvFormData([input.file]);
  formData.set('stepKey', input.stepKey);
  if (input.bootstrapToken) formData.set('bootstrapToken', input.bootstrapToken);

  return readUploadResponse<CsvPreviewResult>(
    await fetch('/api/setup/bootstrap/preview', {
      method: 'POST',
      body: formData
    })
  );
}

export async function previewConfiguredBootstrapCsv(input: {
  bootstrapToken?: string;
} = {}): Promise<CsvPreviewResult> {
  return readUploadResponse<CsvPreviewResult>(
    await fetch('/api/setup/bootstrap/preview', {
      method: 'POST',
      headers: {
        'content-type': 'application/json',
        ...bootstrapHeaders(input.bootstrapToken)
      },
      body: JSON.stringify({
        source: 'configured-directory',
        bootstrapToken: input.bootstrapToken
      })
    })
  );
}

export async function commitSetupCsvFiles(input: {
  files: File[];
  previewHash: string;
  dryRun?: boolean;
}): Promise<ImportReport> {
  const formData = buildCsvFormData(input.files);
  formData.set('previewHash', input.previewHash);
  formData.set('dryRun', String(Boolean(input.dryRun)));

  return readUploadResponse<ImportReport>(
    await fetch('/api/setup/import/commit', {
      method: 'POST',
      body: formData
    })
  );
}

export async function commitConfiguredSetupCsvFiles(input: {
  previewHash: string;
  dryRun?: boolean;
}): Promise<ImportReport> {
  return readUploadResponse<ImportReport>(
    await fetch('/api/setup/import/commit', {
      method: 'POST',
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify({
        source: 'configured-directory',
        previewHash: input.previewHash,
        dryRun: Boolean(input.dryRun)
      })
    })
  );
}

export async function commitBootstrapCsvStep(input: {
  stepKey: string;
  file: File;
  previewHash: string;
  dryRun?: boolean;
  bootstrapToken?: string;
}): Promise<ImportReport> {
  const formData = buildCsvFormData([input.file]);
  formData.set('stepKey', input.stepKey);
  formData.set('previewHash', input.previewHash);
  formData.set('dryRun', String(Boolean(input.dryRun)));
  if (input.bootstrapToken) formData.set('bootstrapToken', input.bootstrapToken);

  return readUploadResponse<ImportReport>(
    await fetch('/api/setup/bootstrap/commit', {
      method: 'POST',
      body: formData
    })
  );
}

export async function commitConfiguredBootstrapCsv(input: {
  previewHash: string;
  dryRun?: boolean;
  bootstrapToken?: string;
}): Promise<ImportReport> {
  return readUploadResponse<ImportReport>(
    await fetch('/api/setup/bootstrap/commit', {
      method: 'POST',
      headers: {
        'content-type': 'application/json',
        ...bootstrapHeaders(input.bootstrapToken)
      },
      body: JSON.stringify({
        source: 'configured-directory',
        previewHash: input.previewHash,
        dryRun: Boolean(input.dryRun),
        bootstrapToken: input.bootstrapToken
      })
    })
  );
}

export async function completeBootstrapSetup(input: CompleteBootstrapSetupPayload): Promise<SetupRunResponse> {
  return apiClient<SetupRunResponse>('/setup/bootstrap/complete', {
    method: 'POST',
    body: JSON.stringify({
      bootstrapToken: input.bootstrapToken,
      report: input.report ?? {}
    })
  });
}
