import type { FillDataResponse, FillFieldData, FillFieldType } from '../domain/types';

const FIELD_TYPES = new Set<FillFieldType>(['text', 'multiline', 'select', 'checkbox', 'date']);

export class FillDataError extends Error {
  constructor(message: string, public readonly status?: number) {
    super(message);
    this.name = 'FillDataError';
  }
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object' && value !== null && !Array.isArray(value);
}

export function parseFillData(raw: unknown): FillDataResponse {
  if (!isRecord(raw) || !isRecord(raw.fields)) throw new Error('填写数据格式无效');
  const fields: Record<string, FillFieldData> = {};
  for (const [tag, value] of Object.entries(raw.fields)) {
    if (!tag || !isRecord(value) || !FIELD_TYPES.has(value.type as FillFieldType)) throw new Error('填写数据格式无效');
    const type = value.type as FillFieldType;
    if (type === 'checkbox') {
      if (value.value !== null && typeof value.value !== 'boolean') throw new Error('填写数据格式无效');
      fields[tag] = { type, value: value.value ?? false };
    } else {
      if (value.value !== null && typeof value.value !== 'string') throw new Error('填写数据格式无效');
      fields[tag] = { type, value: value.value as null | string };
    }
  }
  return { fields };
}

function messageFor(status: number): string {
  if (status === 401) return '填写凭证已过期，请重新打开文档';
  if (status === 403) return '无权读取填写数据';
  if (status === 404) return '填写数据不存在';
  return '填写数据加载失败';
}

export async function fetchFillData(context: { apiBaseUrl: string; ticket: string }): Promise<FillDataResponse> {
  let response: Response;
  try {
    response = await fetch(`${context.apiBaseUrl}/api/eln/onlyoffice/template-fill/data`, {
      headers: { Authorization: `Ticket ${context.ticket}` },
    });
  } catch {
    throw new FillDataError('填写数据加载失败');
  }
  if (!response.ok) throw new FillDataError(messageFor(response.status), response.status);
  try {
    return parseFillData(await response.json());
  } catch (error) {
    if (error instanceof FillDataError) throw error;
    throw new FillDataError('填写数据格式无效');
  }
}
