import { format } from 'date-fns';

import { FileTypes } from 'src/types/attachments';
import {
  type FormAttributes,
  InputType,
  type Question,
  type QuestionSubmitData,
} from 'src/types/forms';

/**
 * InputSign stores a FileAsset ({ id, url, type, … }) but formatValue for
 * DIGITAL_SIGN expects { answer: [{ url, type }] }.  This runs before
 * formatValues so the shared helper receives the shape it needs.
 */
export const normalizeDigitalSignValues = (
  values: Record<string, unknown>,
): Record<string, unknown> => {
  const result = { ...values };
  for (const key of Object.keys(result)) {
    if (!key.includes(InputType.DIGITAL_SIGN) || !result[key]) continue;

    const fileAsset = result[key] as { url?: string; type?: string };
    if (fileAsset.url) {
      result[key] = {
        answer: [
          { url: fileAsset.url, type: fileAsset.type || FileTypes.IMAGE },
        ],
      };
    }
  }
  return result;
};

export const buildQuestionMap = (steps: FormAttributes['steps']) => {
  const map = new Map<number, Question>();
  for (const step of steps) {
    for (const q of step.questions ?? []) {
      map.set(q.id, q);
    }
  }
  return map;
};

export const transformCheckboxAnswer = (
  answer: unknown[],
  options: Question['options'],
): string[] =>
  answer.flat().map(val => {
    const index = typeof val === 'number' ? val : Number(val);
    return options?.[index]?.description ?? String(val);
  });

const transformDropdownAnswer = (answer: unknown[]): string[] =>
  answer.map(val =>
    typeof val === 'object' && val !== null && 'label' in val
      ? String((val as { label: string }).label)
      : String(val),
  );

export const transformQuestionAnswers = (
  questions: QuestionSubmitData[],
  questionMap: Map<number, Question>,
): QuestionSubmitData[] =>
  questions.map(q => {
    const questionDef = questionMap.get(q.id);

    if (
      q.inputType === InputType.CHECKBOX &&
      q.answer &&
      questionDef?.options
    ) {
      return {
        ...q,
        answer: transformCheckboxAnswer(q.answer, questionDef.options),
      };
    }

    if (q.inputType === InputType.DROPDOWN && q.answer) {
      return { ...q, answer: transformDropdownAnswer(q.answer) };
    }

    return q;
  });

export const getQuestionName = (question: Question): string =>
  `${question.inputType}-${question.multipleAnswer}-${question.id}`;

const removeQueryParamMapper = (values: { url?: string }[]) =>
  values.map(e => ({ ...e, url: e.url?.split('?')[0] }));

const formatValue = (key: string, value: unknown) => {
  if (key === 'phoneCode') return null;
  if (!value && value !== 0) return null;

  const keyFragments = key.split('-');
  const inputType = keyFragments[2];

  const propertiesAnswer = {
    id: Number(keyFragments[4]),
    inputType,
  };

  if (inputType === InputType.CHECKBOX && keyFragments[3] === 'true') {
    if (!Object.values(value as object).length) return null;
    return {
      ...propertiesAnswer,
      answer: Object.values(value as object),
    };
  }
  if (inputType === InputType.FILE) {
    return {
      ...propertiesAnswer,
      attachments: removeQueryParamMapper(value as { url?: string }[]),
    };
  }
  if (inputType === InputType.MEDIA) {
    const media = value as {
      images?: { url?: string }[];
      videos?: { url?: string }[];
    };
    if (media?.images?.length === 0 && media?.videos?.length === 0) {
      return null;
    }
    return {
      ...propertiesAnswer,
      attachments: [
        ...(Array.isArray(media.images)
          ? removeQueryParamMapper(media.images)
          : []),
        ...(Array.isArray(media.videos)
          ? removeQueryParamMapper(media.videos)
          : []),
      ],
    };
  }
  if (inputType === InputType.DIGITAL_SIGN) {
    return {
      ...propertiesAnswer,
      attachments: removeQueryParamMapper(
        (value as { answer: { url?: string }[] }).answer,
      ),
    };
  }
  if (inputType === InputType.DATE) {
    return {
      ...propertiesAnswer,
      answer: [format(value as Date, 'dd/MM/yyyy')],
    };
  }
  if (inputType === InputType.DATE_MMAAAA) {
    return {
      ...propertiesAnswer,
      answer: [format(value as Date, 'MM/yyyy')],
    };
  }
  if (inputType === InputType.DATE_MMDDYYYY) {
    return {
      ...propertiesAnswer,
      answer: [format(value as Date, 'MM/dd/yyyy')],
    };
  }
  if (inputType === InputType.TIME) {
    return {
      ...propertiesAnswer,
      answer: [format(value as Date, 'HH:mm')],
    };
  }
  if (inputType === InputType.DECIMAL) {
    return {
      ...propertiesAnswer,
      answer: [String(value).replace(',', '.')],
    };
  }
  if (inputType === InputType.PHONE) {
    if ((value as string).length <= 4) return null;
    return {
      ...propertiesAnswer,
      answer: [value],
    };
  }
  if (inputType === InputType.CHECKBOX_GRID) {
    const rows: { id: number; answer: unknown }[] = [];
    const entries = Object.entries(value as Record<string, unknown>);
    if (!entries.length) return null;
    for (const [id, answer] of entries) {
      rows.push({ id: Number(id), answer });
    }
    return {
      ...propertiesAnswer,
      rows,
    };
  }

  return {
    ...propertiesAnswer,
    answer: [value],
  };
};

export const formatValues = (values: Record<string, unknown>) =>
  Object.keys(values)
    .map(key => formatValue(key, values[key]))
    .filter(value => value !== null);

export const getFilteredValues = (
  objValues: Record<string, unknown>,
): Record<string, unknown> => {
  const filteredPairs = Object.entries(objValues).filter(
    ([key]) => !key.includes('AUTOCOMPLETE'),
  );
  return Object.fromEntries(filteredPairs);
};

export const checkEmptyForm = (objValues: unknown[]): boolean =>
  !objValues.some(
    value =>
      value !== undefined &&
      value !== '' &&
      value !== null &&
      (typeof value !== 'object' || Object.keys(value as object).length !== 0),
  );

export const checkEmptyObject = (obj: Record<string, unknown>): boolean => {
  for (const key in obj) {
    if (Object.hasOwn(obj, key)) {
      const value = obj[key];
      const isEmptyObject =
        Object.prototype.toString.call(value) === '[object Object]' &&
        Object.keys(value as object).length === 0;
      const isEmptyArray = Array.isArray(value) && value.length === 0;
      if (
        value !== undefined &&
        value !== null &&
        value !== '' &&
        !isEmptyObject &&
        !isEmptyArray
      ) {
        return false;
      }
    }
  }
  return true;
};
