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

export interface DatasetRefPayload {
  sourceId: null | number | string;
  catalogId?: null | number | string;
  catalogName?: string;
  tableId: null | number | string;
  tableName: string;
  versionId?: null | number | string;
}

export interface ManagedDatasetFieldOption {
  fieldName: string;
  fieldDesc?: string;
  fieldType?: string;
}

export interface ManagedDatasetSchema {
  tableName?: string;
  tableDesc?: string;
  fields: ManagedDatasetFieldOption[];
}

export interface ManagedDatasetOption {
  label: string;
  value: number | string;
  keywords: string;
  sourceName: string;
  sourceType?: string;
  catalogName: string;
  tableName: string;
  datasetRef: DatasetRefPayload;
}

export interface ManagedDatasetSourceOption {
  sourceId: number | string;
  sourceName: string;
  sourceType?: string;
  label: string;
  keywords: string;
  tables: ManagedDatasetOption[];
}

const SOURCE_MISSING_MESSAGE = '连接不存在';
const SOURCE_UNAVAILABLE_MESSAGE = '当前连接不可用，请检查连接配置后重试';

function shouldSkipSourceError(error: any) {
  const responseData = error?.response?.data ?? {};
  const message = String(responseData?.message ?? error?.message ?? '');

  return (
    message.includes(SOURCE_MISSING_MESSAGE) ||
    message.includes(SOURCE_UNAVAILABLE_MESSAGE)
  );
}

function dedupeManagedDatasetOptions(options: ManagedDatasetOption[]) {
  const uniqueOptions = new Map<string, ManagedDatasetOption>();
  for (const option of options || []) {
    const tableId = option.datasetRef?.tableId;
    const key =
      tableId === null || tableId === undefined
        ? [
            option.datasetRef?.sourceId ?? '',
            option.datasetRef?.catalogId ?? '',
            option.tableName ?? '',
          ].join(':')
        : String(tableId);
    if (!uniqueOptions.has(key)) {
      uniqueOptions.set(key, option);
    }
  }
  return [...uniqueOptions.values()];
}

export async function loadManagedDatasetOptions(): Promise<
  ManagedDatasetOption[]
> {
  const sourceRes = await api.get('/api/v1/datacenterSource/page', {
    params: {
      pageNumber: 1,
      pageSize: 200,
    },
  });
  const sources = sourceRes.data?.records || [];
  const options: ManagedDatasetOption[] = [];
  for (const source of sources) {
    try {
      const catalogRes = await api.get('/api/v1/datacenterSource/catalogs', {
        params: {
          sourceId: source.id,
        },
      });
      const catalogs = catalogRes.data || [];
      for (const catalog of catalogs) {
        const tableRes = await api.get(
          '/api/v1/datacenterDataset/managedTables',
          {
            params: {
              sourceId: source.id,
              catalogId: catalog.id,
            },
          },
        );
        const tables = tableRes.data || [];
        for (const table of tables) {
          const label = `${source.sourceName} / ${catalog.catalogName} / ${table.tableName}`;
          options.push({
            label,
            value: table.id,
            keywords:
              `${source.sourceName} ${catalog.catalogName} ${table.tableName}`.toLowerCase(),
            sourceName: source.sourceName,
            sourceType: source.sourceType,
            catalogName: catalog.catalogName,
            tableName: table.tableName,
            datasetRef: {
              sourceId: source.id,
              catalogId: catalog.id,
              catalogName: catalog.catalogName,
              tableId: table.id,
              tableName: table.tableName,
            },
          });
        }
      }
    } catch (error) {
      if (shouldSkipSourceError(error)) {
        continue;
      }
      throw error;
    }
  }
  return dedupeManagedDatasetOptions(options);
}

export function groupManagedDatasetOptions(
  options: ManagedDatasetOption[],
): ManagedDatasetSourceOption[] {
  const grouped = new Map<number | string, ManagedDatasetSourceOption>();
  for (const option of dedupeManagedDatasetOptions(options || [])) {
    const sourceId = option.datasetRef?.sourceId;
    if (sourceId === null || sourceId === undefined) {
      continue;
    }
    if (!grouped.has(sourceId)) {
      grouped.set(sourceId, {
        sourceId,
        sourceName: option.sourceName,
        sourceType: option.sourceType,
        label: option.sourceName,
        keywords: option.sourceName.toLowerCase(),
        tables: [],
      });
    }
    const group = grouped.get(sourceId);
    if (group) {
      group.tables.push(option);
    }
  }
  return [...grouped.values()].map((item) => ({
    ...item,
    keywords: `${item.sourceName} ${item.tables
      .map((table) => `${table.catalogName} ${table.tableName}`)
      .join(' ')}`.toLowerCase(),
    tables: item.tables.sort((a, b) => a.label.localeCompare(b.label)),
  }));
}

export async function loadManagedDatasetSchema(
  datasetRef?: DatasetRefPayload | null,
): Promise<ManagedDatasetSchema> {
  if (!datasetRef?.tableId) {
    return {
      tableName: datasetRef?.tableName,
      fields: [],
    };
  }
  const res = await api.get('/api/v1/datacenterDataset/schema', {
    params: datasetRef,
  });
  const data = res.data || {};
  const fields = Array.isArray(data.fields)
    ? data.fields.map((field: any) => ({
        fieldName: field.fieldName,
        fieldDesc: field.fieldDesc,
        fieldType: field.jdbcType || field.fieldType,
      }))
    : [];
  return {
    tableName: data.table?.tableName || datasetRef.tableName,
    tableDesc: data.table?.tableDesc,
    fields,
  };
}
