import { defHttp } from '#/api/request';

export type FormulaEnabled = 'disabled' | 'enabled';
export type FormulaStatus = 'CANCELLED' | 'DRAFT' | 'PRE_RELEASE' | 'PUBLISHED';
export type FormulaType = 'BOOLEAN' | 'DECIMAL' | 'DECIMAL_LIST' | 'TEXT';
export type RoundMode = 'DOWN' | 'HALF_EVEN' | 'HALF_UP' | 'UP';
export type PreviewStatus = 'ERROR' | 'MISSING_INPUT' | 'SUCCESS';
export type DiagnosticSeverity = 'ERROR' | 'WARNING';
export type FormulaFunctionReturnType = 'BOOLEAN' | 'DECIMAL' | 'DYNAMIC';

export interface ParameterSlot {
  canshuBianma: string;
  canshuMingcheng: string;
  danwei?: string;
  id?: string;
  paixu: number;
  shifouBitian: 0 | 1;
  shujuLeixing: FormulaType;
}

export interface Diagnostic {
  code?: string;
  end: number;
  message?: string;
  severity: DiagnosticSeverity;
  start: number;
}

export interface FormulaRule {
  biaodashi: string;
  jieguoLeixing: FormulaType;
  parameters: ParameterSlot[];
  xiuyueMoshi?: RoundMode;
  xiuyueXiaoshuWei?: number;
}

export interface FormulaValidation {
  diagnostics: Diagnostic[];
  inferredType?: FormulaType;
  latex?: null | string;
}

export interface FormulaPreview {
  diagnostics: Diagnostic[];
  latex?: null | string;
  rawResult?: unknown;
  roundedResult?: unknown;
  status: PreviewStatus;
}

export interface FormulaFunction {
  category: string;
  chineseName: string;
  code: string;
  description: string;
  example: string;
  returnType: FormulaFunctionReturnType;
  signature: string;
}

export interface FormulaPageQuery {
  bizEnabled?: FormulaEnabled;
  currentPage: number;
  keyword?: string;
  pageSize: number;
}

export interface TemplateReferencePageQuery {
  currentPage: number;
  keyword?: string;
  pageSize: number;
}

export interface FormulaListItem {
  bizEnabled: FormulaEnabled;
  dangqianBanbenHao?: number;
  dangqianGongshiBanbenId?: string;
  gengxinShijian?: string;
  gongshiBianma: string;
  gongshiMingcheng: string;
  id: string;
  mubanYinyongShu?: number;
  yewuYongtu?: string;
  zuixinFabuBanbenHao?: number;
}

export interface FormulaVersion extends FormulaRule {
  banbenHao: number;
  bizStatus: FormulaStatus;
  chuangjianShijian?: string;
  gengxinShijian?: string;
  gongshiDingyiId: string;
  id: string;
  zuofeiYuanyin?: string;
}

export interface TemplateReferenceSummary {
  bindingId: string;
  bindingStatus?: string;
  formulaVersionId: string;
  templateId: string;
  templateName?: string;
  templateStatus?: string;
}

export interface FormulaDetail {
  beizhu?: string;
  bizEnabled: FormulaEnabled;
  dangqianGongshiBanbenId?: string;
  gongshiBianma: string;
  gongshiMingcheng: string;
  id: string;
  mubanYinyongShu?: number;
  templateReferences?: TemplateReferenceSummary[];
  versions: FormulaVersion[];
  yewuYongtu?: string;
}

export interface FormulaPage {
  list: FormulaListItem[];
  pagination: { currentPage: number; pageSize: number; total: number };
}

export interface TemplateReferencePage {
  list: TemplateReferenceSummary[];
  pagination: { currentPage: number; pageSize: number; total: number };
}

export interface CreateFormulaParams extends FormulaRule {
  beizhu?: string;
  gongshiMingcheng: string;
  yewuYongtu?: string;
}

export interface CreateFormulaDraftParams {
  beizhu?: string;
  gongshiMingcheng: string;
  parameters: ParameterSlot[];
  yewuYongtu?: string;
}

export interface UpdateFormulaDefinitionParams {
  beizhu?: string;
  gongshiMingcheng: string;
  yewuYongtu?: string;
}

export interface CreateFormulaVersionParams {
  sourceVersionId: string;
}

export interface PreviewFormulaParams extends FormulaRule {
  inputs: Record<string, Array<null | number | string> | boolean | null | number | string>;
}

export interface SwitchCurrentFormulaVersionParams {
  reason: string;
  versionId: string;
}

interface ApiResult<T> {
  code: number;
  data: T;
  msg?: string;
}

const FORMULA_CATALOG_PREFIX = '/api/eln/formulaCatalog';
const formulaFunctionByCode = new Map<string, FormulaFunction>();
let formulaFunctionsLoaded = false;
let formulaFunctionsRequest: Promise<FormulaFunction[]> | undefined;

export function getFormulaPage(data: FormulaPageQuery) {
  return defHttp.get<ApiResult<FormulaPage>>({ data, url: FORMULA_CATALOG_PREFIX });
}

export function createFormula(data: CreateFormulaParams) {
  return defHttp.post<ApiResult<FormulaDetail>>({ data, url: FORMULA_CATALOG_PREFIX });
}

export function createFormulaDraft(data: CreateFormulaDraftParams) {
  return defHttp.post<ApiResult<FormulaDetail>>({ data, url: `${FORMULA_CATALOG_PREFIX}/drafts` });
}

export function getFormulaDetail(id: string) {
  return defHttp.get<ApiResult<FormulaDetail>>({ url: `${FORMULA_CATALOG_PREFIX}/${id}` });
}

export function getFormulaTemplateReferences(id: string, data: TemplateReferencePageQuery) {
  return defHttp.get<ApiResult<TemplateReferencePage>>({ data, url: `${FORMULA_CATALOG_PREFIX}/${id}/templateReferences` });
}

export function updateFormulaDefinition(id: string, data: UpdateFormulaDefinitionParams) {
  return defHttp.put<ApiResult<FormulaDetail>>({ data, url: `${FORMULA_CATALOG_PREFIX}/${id}` });
}

export function getFormulaFunctions(): Promise<FormulaFunction[]> {
  if (formulaFunctionsLoaded) return Promise.resolve([...formulaFunctionByCode.values()]);
  if (formulaFunctionsRequest) return formulaFunctionsRequest;

  formulaFunctionsRequest = defHttp
    .get<ApiResult<FormulaFunction[]>>({ url: `${FORMULA_CATALOG_PREFIX}/functions` })
    .then((response) => {
      for (const formula of response.data) formulaFunctionByCode.set(formula.code, formula);
      formulaFunctionsLoaded = true;
      return [...formulaFunctionByCode.values()];
    })
    .finally(() => {
      formulaFunctionsRequest = undefined;
    });
  return formulaFunctionsRequest;
}

export function validateFormula(data: FormulaRule, signal?: AbortSignal) {
  return defHttp.post<ApiResult<FormulaValidation>>({ data, signal, url: `${FORMULA_CATALOG_PREFIX}/validate` });
}

export function previewFormula(data: PreviewFormulaParams, signal?: AbortSignal) {
  return defHttp.post<ApiResult<FormulaPreview>>({ data, signal, url: `${FORMULA_CATALOG_PREFIX}/preview` });
}

export function createFormulaVersion(formulaId: string, data: CreateFormulaVersionParams) {
  return defHttp.post<ApiResult<FormulaVersion>>({ data, url: `${FORMULA_CATALOG_PREFIX}/${formulaId}/versions` });
}

export function updateFormulaVersion(versionId: string, data: FormulaRule) {
  return defHttp.put<ApiResult<FormulaVersion>>({ data, url: `${FORMULA_CATALOG_PREFIX}/versions/${versionId}` });
}

export function preReleaseFormulaVersion(versionId: string) {
  return defHttp.post<ApiResult<void>>({ url: `${FORMULA_CATALOG_PREFIX}/versions/${versionId}/preRelease` });
}

export function publishFormulaVersion(versionId: string) {
  return defHttp.post<ApiResult<void>>({ url: `${FORMULA_CATALOG_PREFIX}/versions/${versionId}/publish` });
}

export function cancelFormulaVersion(versionId: string, reason: string) {
  return defHttp.post<ApiResult<void>>({ data: { reason }, url: `${FORMULA_CATALOG_PREFIX}/versions/${versionId}/cancel` });
}

export function switchCurrentFormulaVersion(formulaId: string, data: SwitchCurrentFormulaVersionParams) {
  return defHttp.post<ApiResult<void>>({ data, url: `${FORMULA_CATALOG_PREFIX}/${formulaId}/currentVersion` });
}

export function enableFormula(formulaId: string, reason: string) {
  return defHttp.post<ApiResult<void>>({ data: { reason }, url: `${FORMULA_CATALOG_PREFIX}/${formulaId}/enable` });
}

export function disableFormula(formulaId: string, reason: string) {
  return defHttp.post<ApiResult<void>>({ data: { reason }, url: `${FORMULA_CATALOG_PREFIX}/${formulaId}/disable` });
}
