import { getHttpClient, apiErrorMessage } from './http';

export interface PdfDownload {
  base64: string;
  filename: string;
}

function filenameFromDisposition(header: string | undefined, fallback: string): string {
  if (!header) return fallback;
  const match = /filename\*?=(?:UTF-8''|")?([^\";]+)/i.exec(header);
  if (!match?.[1]) return fallback;
  try {
    return decodeURIComponent(match[1].replace(/"/g, '').trim());
  } catch {
    return match[1].replace(/"/g, '').trim() || fallback;
  }
}

function arrayBufferToBase64(buffer: ArrayBuffer): string {
  const bytes = new Uint8Array(buffer);
  const chars: string[] = [];
  const chunk = 0x8000;
  for (let i = 0; i < bytes.length; i += chunk) {
    const slice = bytes.subarray(i, i + chunk);
    chars.push(String.fromCharCode.apply(null, Array.from(slice) as unknown as number[]));
  }
  return globalThis.btoa(chars.join(''));
}

async function downloadPdf(
  path: string,
  fallbackName: string,
  params?: Record<string, string | number | null | undefined>,
): Promise<PdfDownload> {
  const { client } = await getHttpClient();
  try {
    const cleanParams: Record<string, string | number> = {};
    if (params) {
      for (const [k, v] of Object.entries(params)) {
        if (v != null && v !== '') cleanParams[k] = v;
      }
    }
    const res = await client.get<ArrayBuffer>(path, {
      responseType: 'arraybuffer',
      headers: { Accept: 'application/pdf' },
      timeout: 120000,
      params: cleanParams,
    });
    const contentType = String(res.headers['content-type'] ?? '');
    if (contentType.includes('application/json')) {
      throw new Error('PDF indisponible pour ce document.');
    }
    const filename = filenameFromDisposition(
      res.headers['content-disposition'] as string | undefined,
      fallbackName,
    );
    return {
      base64: arrayBufferToBase64(res.data),
      filename: filename.endsWith('.pdf') ? filename : `${filename}.pdf`,
    };
  } catch (err) {
    throw new Error(apiErrorMessage(err));
  }
}

/** Offer / reservation PDF (new CRM: /pdf/reservation/{id}?model_id=). */
export async function downloadOfferPdf(
  offerId: number,
  modelId?: number | null,
): Promise<PdfDownload> {
  const { config } = await getHttpClient();
  const params = modelId && modelId > 0 ? { model_id: modelId } : undefined;
  if (config.mode === 'legacy') {
    return downloadPdf(`/mobile/offers/${offerId}/pdf`, `offre_${offerId}.pdf`, params);
  }
  try {
    return await downloadPdf(`/pdf/reservation/${offerId}`, `offre_${offerId}.pdf`, params);
  } catch {
    return downloadPdf(`/mobile/offers/${offerId}/pdf`, `offre_${offerId}.pdf`, params);
  }
}

/**
 * Same PDF set as CRM WhatsApp offer send: cover letter (if any) + fiches bien + docs projet.
 */
export async function downloadOfferWhatsappPdfs(
  offerId: number,
  modelId?: number | null,
): Promise<PdfDownload[]> {
  const { client } = await getHttpClient();
  const params =
    modelId && modelId > 0 ? { model_id: modelId } : ({} as Record<string, number>);

  try {
    const { data } = await client.get<{
      data?: { files?: Array<{ name?: string; base64?: string; mime?: string }> };
      files?: Array<{ name?: string; base64?: string; mime?: string }>;
    }>(`/mobile/offers/${offerId}/whatsapp-attachments`, {
      params,
      timeout: 180000,
      headers: { Accept: 'application/json' },
    });
    const raw = data.data?.files ?? data.files ?? [];
    const files = raw
      .filter((f) => f?.base64)
      .map((f, i) => ({
        base64: String(f.base64),
        filename: (f.name && f.name.endsWith('.pdf') ? f.name : f.name ? `${f.name}.pdf` : null)
          || `offre_${offerId}_${i + 1}.pdf`,
      }));
    if (files.length > 0) {
      return files;
    }
  } catch {
    // Fallback: /pdf?full=1 may return the same JSON shape on older deploys
  }

  try {
    const { data } = await client.get<{
      data?: { files?: Array<{ name?: string; base64?: string }> };
    }>(`/mobile/offers/${offerId}/pdf`, {
      params: { ...params, full: 1 },
      timeout: 180000,
      headers: { Accept: 'application/json' },
    });
    const raw = data.data?.files ?? [];
    const files = raw
      .filter((f) => f?.base64)
      .map((f, i) => ({
        base64: String(f.base64),
        filename: (f.name && String(f.name).endsWith('.pdf') ? String(f.name) : null)
          || `offre_${offerId}_${i + 1}.pdf`,
      }));
    if (files.length > 0) {
      return files;
    }
  } catch {
    // last resort: single cover PDF
  }

  const single = await downloadOfferPdf(offerId, modelId);
  return [single];
}

/** Property fiche PDF — classic CRM model via classic_model_id / modelId. */
export async function downloadPropertyPdf(
  propertyId: number,
  modelId?: number | null,
): Promise<PdfDownload> {
  const { config } = await getHttpClient();
  if (config.mode === 'legacy') {
    const params =
      modelId && modelId > 0 ? { modelId, model_id: modelId } : undefined;
    try {
      return await downloadPdf(`/properties/${propertyId}/download`, `bien_${propertyId}.pdf`, params);
    } catch {
      return downloadPdf(`/mobile/properties/${propertyId}/pdf`, `bien_${propertyId}.pdf`, params);
    }
  }
  const params =
    modelId && modelId > 0 ? { classic_model_id: modelId, model_id: modelId } : undefined;
  try {
    return await downloadPdf(`/pdf/property/${propertyId}`, `bien_${propertyId}.pdf`, params);
  } catch {
    return downloadPdf(`/mobile/properties/${propertyId}/pdf`, `bien_${propertyId}.pdf`, params);
  }
}

export { apiErrorMessage };
