// ═══════════════════════════════════════════════════════════════════════
// Previous NC — API client
// ═══════════════════════════════════════════════════════════════════════

import type {
  ListPreviousNcsParams,
  PreviousNcDetailResponse,
  PreviousNcPagedResponse,
  PreviousNcUserOption,
  NcSource,
  UpdatePreviousNcDto,
  UpdatePreviousNcResponse,
  ClosureResponse,
  SaveClosurePayload,
  SaveClosureResponse,
  AuditNcStatusParams,
  AuditNcStatusResponse,
} from './types/previous-nc.types';

const API_BASE =
  process.env.NEXT_PUBLIC_API_URL?.replace(/\/api$/, '') ||
  process.env.NEXT_PUBLIC_API_BASE_URL?.replace(/\/api$/, '') ||
  '';

function getAuthToken(): string {
  if (typeof window === 'undefined') return '';
  return (
    localStorage.getItem('access_token') ||
    sessionStorage.getItem('access_token') ||
    localStorage.getItem('token') ||
    localStorage.getItem('authToken') ||
    ''
  );
}

function authHeaders(): HeadersInit {
  const token = getAuthToken();
  return token
    ? { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }
    : { 'Content-Type': 'application/json' };
}

async function handle<T>(res: Response): Promise<T> {
  if (!res.ok) {
    let detail = '';
    try {
      const body = await res.json();
      detail =
        body?.message ||
        body?.error ||
        (typeof body === 'string' ? body : '');
      if (Array.isArray(detail)) detail = detail.join('; ');
    } catch {
      try {
        detail = await res.text();
      } catch {}
    }
    throw new Error(
      `${res.status} ${res.statusText}${detail ? ` — ${detail}` : ''}`,
    );
  }
  return res.json();
}

// ═══════════════════════════════════════════════════════════════════════
// EXISTING ENDPOINTS (unchanged)
// ═══════════════════════════════════════════════════════════════════════

export async function getPreviousNcsPaged(
  params: ListPreviousNcsParams = {},
): Promise<PreviousNcPagedResponse> {
  const qs = new URLSearchParams();
  if (params.page) qs.set('page', String(params.page));
  if (params.limit) qs.set('limit', String(params.limit));
  if (params.source && params.source !== 'All') qs.set('source', params.source);
  if (params.status && params.status !== 'All') qs.set('status', params.status);
  if (params.nc_type && params.nc_type !== 'All')
    qs.set('nc_type', params.nc_type);
  if (params.audit_type && params.audit_type !== 'All')
    qs.set('audit_type', params.audit_type);
  if (params.search) qs.set('search', params.search);
  if (params.date_from) qs.set('date_from', params.date_from);
  if (params.date_to) qs.set('date_to', params.date_to);
  if (params.user_name) qs.set('user_name', params.user_name);

  const url = `${API_BASE}/api/previous-nc/paged?${qs.toString()}`;
  const res = await fetch(url, { headers: authHeaders(), cache: 'no-store' });
  return handle<PreviousNcPagedResponse>(res);
}

export async function getPreviousNcUsers(): Promise<PreviousNcUserOption[]> {
  const url = `${API_BASE}/api/previous-nc/users`;
  const res = await fetch(url, { headers: authHeaders(), cache: 'no-store' });
  return handle<PreviousNcUserOption[]>(res);
}

export async function getPreviousNc(
  source: NcSource,
  id: number,
): Promise<PreviousNcDetailResponse> {
  const url = `${API_BASE}/api/previous-nc/${source}/${id}`;
  const res = await fetch(url, { headers: authHeaders(), cache: 'no-store' });
  return handle<PreviousNcDetailResponse>(res);
}

export async function updatePreviousNc(
  source: NcSource,
  id: number,
  payload: UpdatePreviousNcDto,
): Promise<UpdatePreviousNcResponse> {
  const url = `${API_BASE}/api/previous-nc/${source}/${id}`;
  const res = await fetch(url, {
    method: 'PATCH',
    headers: authHeaders(),
    body: JSON.stringify(payload),
  });
  return handle<UpdatePreviousNcResponse>(res);
}

export function getPreviousNcPdfUrl(source: NcSource, id: number): string {
  return `${API_BASE}/api/previous-nc/${source}/${id}/pdf`;
}

export function getPreviousNcAttendanceUrl(
  source: NcSource,
  id: number,
): string {
  return `${API_BASE}/api/previous-nc/${source}/${id}/attendance-pdf`;
}

export async function fetchPreviousNcPdfBlob(
  source: NcSource,
  id: number,
): Promise<string> {
  const url = getPreviousNcPdfUrl(source, id);
  const res = await fetch(url, { headers: authHeaders() });
  if (!res.ok) {
    let detail = '';
    try {
      detail = (await res.json())?.message || '';
    } catch {}
    throw new Error(
      `Failed to fetch PDF: ${res.status} ${res.statusText}${detail ? ` — ${detail}` : ''}`,
    );
  }
  const blob = await res.blob();
  return URL.createObjectURL(blob);
}

export async function fetchPreviousNcAttendanceBlob(
  source: NcSource,
  id: number,
): Promise<string> {
  const url = getPreviousNcAttendanceUrl(source, id);
  const res = await fetch(url, { headers: authHeaders() });
  if (!res.ok) {
    let detail = '';
    try {
      detail = (await res.json())?.message || '';
    } catch {}
    throw new Error(
      `Failed to fetch attendance PDF: ${res.status} ${res.statusText}${detail ? ` — ${detail}` : ''}`,
    );
  }
  const blob = await res.blob();
  return URL.createObjectURL(blob);
}

// ═══════════════════════════════════════════════════════════════════════
// 🆕 PHASE 1 — EVIDENCE ENDPOINTS
// ═══════════════════════════════════════════════════════════════════════

export interface UploadEvidenceResponse {
  ok: true;
  entry_id: number;
  document_path: string;
  filename: string;
  size: number;
  uploaded_at: string;
}

export async function uploadEntryEvidence(
  source: NcSource,
  ncId: number,
  entryId: number,
  file: File,
  onProgress?: (percent: number) => void,
): Promise<UploadEvidenceResponse> {
  const url = `${API_BASE}/api/previous-nc/${source}/${ncId}/entries/${entryId}/evidence`;

  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    const formData = new FormData();
    formData.append('file', file);

    xhr.open('POST', url);

    const token = getAuthToken();
    if (token) {
      xhr.setRequestHeader('Authorization', `Bearer ${token}`);
    }

    xhr.upload.onprogress = (e) => {
      if (e.lengthComputable && onProgress) {
        onProgress(Math.round((e.loaded / e.total) * 100));
      }
    };

    xhr.onload = () => {
      if (xhr.status >= 200 && xhr.status < 300) {
        try {
          resolve(JSON.parse(xhr.responseText));
        } catch (e) {
          reject(new Error('Invalid response from server'));
        }
      } else {
        let msg = `Upload failed: ${xhr.status} ${xhr.statusText}`;
        try {
          const body = JSON.parse(xhr.responseText);
          if (body?.message) {
            msg = Array.isArray(body.message)
              ? body.message.join('; ')
              : body.message;
          }
        } catch {}
        reject(new Error(msg));
      }
    };

    xhr.onerror = () => reject(new Error('Network error during upload'));
    xhr.onabort = () => reject(new Error('Upload aborted'));

    xhr.send(formData);
  });
}

export async function deleteEntryEvidence(
  source: NcSource,
  ncId: number,
  entryId: number,
): Promise<{ ok: true; entry_id: number; deleted_file: boolean }> {
  const url = `${API_BASE}/api/previous-nc/${source}/${ncId}/entries/${entryId}/evidence`;
  const res = await fetch(url, {
    method: 'DELETE',
    headers: authHeaders(),
  });
  return handle(res);
}

export function getEntryFileUrl(
  source: NcSource,
  ncId: number,
  entryId: number,
): string {
  return `${API_BASE}/api/previous-nc/${source}/${ncId}/entries/${entryId}/file`;
}

export async function fetchEntryFileBlob(
  source: NcSource,
  ncId: number,
  entryId: number,
): Promise<string> {
  const url = getEntryFileUrl(source, ncId, entryId);
  const res = await fetch(url, { headers: authHeaders() });
  if (!res.ok) {
    let detail = '';
    try {
      detail = (await res.json())?.message || '';
    } catch {}
    throw new Error(
      `Failed to fetch file: ${res.status} ${res.statusText}${detail ? ` — ${detail}` : ''}`,
    );
  }
  const blob = await res.blob();
  return URL.createObjectURL(blob);
}

// ═══════════════════════════════════════════════════════════════════════
// 🆕 PHASE 1 v3 — DELETE ENTRY (whole finding)
// ═══════════════════════════════════════════════════════════════════════

export interface DeleteEntryResponse {
  ok: true;
  entry_id: number;
  deleted_file: boolean;
}

/**
 * Delete an entire finding (ncr_entries row).
 * Backend will:
 *   - Permission check (owner or admin/coordinator/scheme role)
 *   - Delete the evidence file ONLY if it's a new-format file (legacy untouched)
 *   - Delete the ncr_entries row
 */

export async function deletePreviousNc(
  source: NcSource,
  id: number,
): Promise<{ ok: true }> {
  const url = `${API_BASE}/api/previous-nc/${source}/${id}`;
  const res = await fetch(url, {
    method: 'DELETE',
    headers: authHeaders(),
  });
  return handle(res);
}
export async function deleteEntry(
  source: NcSource,
  ncId: number,
  entryId: number,
): Promise<DeleteEntryResponse> {
  const url = `${API_BASE}/api/previous-nc/${source}/${ncId}/entries/${entryId}`;
  const res = await fetch(url, {
    method: 'DELETE',
    headers: authHeaders(),
  });
  return handle(res);
}

// ═══════════════════════════════════════════════════════════════════════
// 🆕 PHASE 2A — CLOSURE ENDPOINTS
// ═══════════════════════════════════════════════════════════════════════

/**
 * Fetch current closure state for an NC.
 * Returns empty rows + defaults if no closure exists yet.
 */
export async function getNcClosure(
  source: NcSource,
  ncId: number,
): Promise<ClosureResponse> {
  const url = `${API_BASE}/api/previous-nc/${source}/${ncId}/closure`;
  const res = await fetch(url, { headers: authHeaders(), cache: 'no-store' });
  return handle<ClosureResponse>(res);
}

/**
 * Save closure (draft or finalize).
 * Sends multipart/form-data with optional signed_copy + signature files
 * plus JSON-stringified payload fields.
 */
export async function saveNcClosure(
  source: NcSource,
  ncId: number,
  payload: SaveClosurePayload,
  onProgress?: (percent: number) => void,
): Promise<SaveClosureResponse> {
  const url = `${API_BASE}/api/previous-nc/${source}/${ncId}/closure`;

  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    const formData = new FormData();

    formData.append(
      'closed_entry_ids',
      JSON.stringify(payload.closed_entry_ids),
    );
    formData.append(
      'rows',
      JSON.stringify(
        payload.rows.map((r) => ({
          entry_id: r.entry_id,
          evidence_received: r.evidence_received,
          submitted_docs: r.submitted_docs,
          result_accepted: r.result_accepted,
          remarks: r.remarks,
        })),
      ),
    );
    formData.append(
      'verification_by_auditor',
      payload.verification_by_auditor,
    );
    formData.append('auditor_name', payload.auditor_name);
    formData.append('closure_date', payload.closure_date);
    formData.append('send_to_client', String(payload.send_to_client));
    formData.append('finalize', String(payload.finalize));

    if (payload.signed_copy) {
      formData.append('signed_copy', payload.signed_copy);
    }
    if (payload.signature) {
      formData.append('signature', payload.signature);
    }

    xhr.open('POST', url);

    const token = getAuthToken();
    if (token) {
      xhr.setRequestHeader('Authorization', `Bearer ${token}`);
    }

    xhr.upload.onprogress = (e) => {
      if (e.lengthComputable && onProgress) {
        onProgress(Math.round((e.loaded / e.total) * 100));
      }
    };

    xhr.onload = () => {
      if (xhr.status >= 200 && xhr.status < 300) {
        try {
          resolve(JSON.parse(xhr.responseText));
        } catch (e) {
          reject(new Error('Invalid response from server'));
        }
      } else {
        let msg = `Save failed: ${xhr.status} ${xhr.statusText}`;
        try {
          const body = JSON.parse(xhr.responseText);
          if (body?.message) {
            msg = Array.isArray(body.message)
              ? body.message.join('; ')
              : body.message;
          }
        } catch {}
        reject(new Error(msg));
      }
    };

    xhr.onerror = () => reject(new Error('Network error during save'));
    xhr.onabort = () => reject(new Error('Save aborted'));

    xhr.send(formData);
  });
}

/**
 * Open a closure file blob (signed copy or auditor signature).
 * Returns an object URL — caller is responsible for calling URL.revokeObjectURL.
 */
export async function fetchClosureFileBlob(
  source: NcSource,
  ncId: number,
  kind: 'signed_copy' | 'signature',
): Promise<string> {
  const url = `${API_BASE}/api/previous-nc/${source}/${ncId}/closure/file/${kind}`;
  const res = await fetch(url, { headers: authHeaders() });
  if (!res.ok) {
    let detail = '';
    try {
      detail = (await res.json())?.message || '';
    } catch {}
    throw new Error(
      `Failed to fetch ${kind}: ${res.status} ${res.statusText}${detail ? ` — ${detail}` : ''}`,
    );
  }
  const blob = await res.blob();
  return URL.createObjectURL(blob);
}

/**
 * Discard a draft closure (refused if already finalized).
 * Removes all rows + best-effort cleanup of uploaded files.
 */
export async function deleteNcClosure(
  source: NcSource,
  ncId: number,
): Promise<{ ok: true; deleted_rows: number }> {
  const url = `${API_BASE}/api/previous-nc/${source}/${ncId}/closure`;
  const res = await fetch(url, {
    method: 'DELETE',
    headers: authHeaders(),
  });
  return handle(res);
}
// ═══════════════════════════════════════════════════════════════════════
// 🆕 AUDIT-ASSIGN REPORT
// ═══════════════════════════════════════════════════════════════════════

export interface AuditAssignMonth {
  month: string; // 'YYYY-MM'
  total_assigned: number;
  stage1_uploaded: number;
  stage2_uploaded: number;
  initial: number;
  surveillance: number;
  recertification: number;
}

export interface AuditAssignRow {
  user_id: number;
  auditor: string;
  source: 'QRS' | 'TQS' | 'QRS & TQS';
  total_assigned: number;
  stage1_uploaded: number;
  stage1_missing: number;
  stage2_uploaded: number;
  stage2_missing: number;
  initial: number;          // ← ADD
  surveillance: number;     // ← ADD
  recertification: number;  // ← ADD
  months: AuditAssignMonth[];
}

export interface AuditAssignReportResponse {
  rows: AuditAssignRow[];
  totals: {
    total_assigned: number;
    stage1_uploaded: number;
    stage1_missing: number;
    stage2_uploaded: number;
    stage2_missing: number;
    initial: number;          // ← ADD
    surveillance: number;     // ← ADD
    recertification: number;  // ← ADD
  };
}
export async function getAuditNcStatusReport(
  params: AuditNcStatusParams = {},
): Promise<AuditNcStatusResponse> {
  const qs = new URLSearchParams();
  if (params.source && params.source !== 'All') qs.set('source', params.source);
  if (params.status && params.status !== 'All') qs.set('status', params.status);
  if (params.date_from) qs.set('date_from', params.date_from);
  if (params.date_to) qs.set('date_to', params.date_to);
  if (params.search) qs.set('search', params.search);

  const url = `${API_BASE}/api/previous-nc/audit-nc-status?${qs.toString()}`;
  const res = await fetch(url, { headers: authHeaders(), cache: 'no-store' });
  return handle<AuditNcStatusResponse>(res);
}
export async function getAuditAssignReport(): Promise<AuditAssignReportResponse> {
  const url = `${API_BASE}/api/previous-nc/audit-assign-report`;
  const res = await fetch(url, { headers: authHeaders(), cache: 'no-store' });
  return handle<AuditAssignReportResponse>(res);
}

// ═══════════════════════════════════════════════════════════════════════
// 🆕 AUDIT → NC STATUS — server-side Excel / PDF export
// ═══════════════════════════════════════════════════════════════════════

export interface AuditNcStatusExportFilters {
  source?: 'QRS' | 'TQS' | 'All';
  status?: 'Raised' | 'Pending' | 'All';
  auditor?: string;
  year?: number;
  month?: number | 'all';
  search?: string;
}

export async function downloadAuditNcStatusReport(
  format: 'excel' | 'pdf',
  f: AuditNcStatusExportFilters = {},
): Promise<void> {
  const qs = new URLSearchParams();
  Object.entries(f).forEach(([k, v]) => {
    if (v !== undefined && v !== null && v !== '' && v !== 'all' && v !== 'All') {
      qs.set(k, String(v));
    }
  });
  const suffix = qs.toString() ? `?${qs.toString()}` : '';

  const res = await fetch(
    `${API_BASE}/api/previous-nc/audit-nc-status/export/${format}${suffix}`,
    { headers: authHeaders(), cache: 'no-store' },
  );
  if (!res.ok) {
    let detail = '';
    try { detail = (await res.json())?.message || ''; } catch {}
    throw new Error(`Export failed: ${res.status} ${res.statusText}${detail ? ` — ${detail}` : ''}`);
  }
  const blob = await res.blob();
  const url = URL.createObjectURL(blob);
  const ext = format === 'excel' ? 'xlsx' : 'pdf';
  const a = document.createElement('a');
  a.href = url;
  a.download = `audit-nc-status-${new Date().toISOString().slice(0, 10)}.${ext}`;
  document.body.appendChild(a);
  a.click();
  a.remove();
  setTimeout(() => URL.revokeObjectURL(url), 10_000);
}