import { ApiError } from '../common/error/api-error';
import { ApiErrorCodes } from '../common/error/api-error-codes';
import { AssetWhereRequestDTO } from './dto/asset-dto';
import {
  AssetQueryDTO,
  AssetViewQueryDTO,
  AssetViewQueryPostDTO,
} from './dto/asset-query-dto';
import { isAggregateAssetPropsSelectionField } from './logic/AssetSelectorQuery';
import {
  AssetPropsSelectionBase,
  AssetPropsSelection,
} from './logic/PropsSelection';
import { AssetPropWhere } from './logic/PropsWhere';
import {
  validateAssetPropsSelectionBase,
  validateAssetPropsSelection,
  validateAssetPropsWhere,
} from './logic/validatePropsSelection';

export const ASSET_BASE_ORDERING = [
  'index',
  'title',
  'name',
  'createdAt',
  'id',
];
export const ASSET_GET_MAX_COUNT = 1000;

export function parseAssetQueryField<T>(value: any, field: string, def: T): T {
  if (value) {
    try {
      return JSON.parse(value);
    } catch (err: any) {
      throw new ApiError(
        'Cannot parse asset query',
        ApiErrorCodes.PARAM_BAD_FORMAT,
        {
          field,
          error: err.message,
        },
      );
    }
  } else return def;
}

export function convertAssetQueryToSelectionBase(
  filterData: AssetQueryDTO,
): AssetPropsSelectionBase {
  const order_parsed = parseAssetQueryField<any[]>(
    filterData.order,
    'order',
    [],
  );
  const where_parsed = parseAssetQueryField<any>(filterData.where, 'where', {});
  const res = validateAssetPropsSelectionBase({
    where: where_parsed,
    order: order_parsed,
    offset: filterData.offset,
    count: filterData.count,
  });
  if (!res.count || res.count > ASSET_GET_MAX_COUNT) {
    res.count = ASSET_GET_MAX_COUNT;
  }
  if (!res.order || res.order.length === 0) {
    res.order = ASSET_BASE_ORDERING;
  }
  return res;
}

export function convertAssetQueryToPostFormat(
  filterData: AssetViewQueryDTO,
): AssetViewQueryPostDTO {
  return {
    select: parseAssetQueryField<any[]>(filterData.select, 'select', []),
    order: filterData.order
      ? parseAssetQueryField<any[]>(filterData.order, 'order', [])
      : undefined,
    count: filterData.count,
    offset: filterData.offset,
    group: filterData.group
      ? parseAssetQueryField<any[]>(filterData.group, 'group', [])
      : undefined,
    where: filterData.where
      ? parseAssetQueryField<any>(filterData.where, 'where', {})
      : undefined,
  };
}

export function convertAssetQueryToSelection(
  filterData: AssetViewQueryPostDTO,
): AssetPropsSelection {
  const res = validateAssetPropsSelection(filterData);
  if (!res.count || res.count > ASSET_GET_MAX_COUNT) {
    res.count = ASSET_GET_MAX_COUNT;
  }
  if (
    (!res.group || res.group.length === 0) &&
    res.select.every((s) => !isAggregateAssetPropsSelectionField(s))
  ) {
    if (!res.order || res.order.length === 0) {
      res.order = ASSET_BASE_ORDERING;
    }
  }
  return res;
}

export function convertAssetWhereRequestToWhere(
  request: AssetWhereRequestDTO,
): AssetPropWhere {
  const where = validateAssetPropsWhere(request.where);
  const conds = Object.entries(where);
  if (conds.length === 0) {
    throw new ApiError(
      'You must specify at least one condition',
      ApiErrorCodes.PARAM_BAD_FORMAT,
    );
  }
  return where;
}
