import { TableColumn } from '@/interfaces';
import { WithScopeAccess } from '@/interfaces/entities/Access';
import { ColumnTypeEnum } from '@/openapi/document-converter';
import cloneDeep from 'lodash/cloneDeep';
import isEmpty from 'lodash/isEmpty';
import { Columns } from '../';
import { FieldType } from '@/components/cards/services/Export/types';
import get from 'lodash/get';
import set from 'lodash/set';
import { i18n } from '@plugins/i18n';
import { ServiceMapping } from '@/openapi/registry-service';

const localStorageColumnsName = 'statements-columns';

export function createDefaultColumn(
  field: string,
  label: string
): WithScopeAccess<TableColumn> {
  return {
    data: {
      align: 'left',
      field,
      format: (val: any) => {
        if (val) {
          return val;
        }
        return '';
      },
      label,
      name: field,
      required: true,
      sortable: true,
      style: 'white-space: normal;'
    },
  };
}

export function getKey(column: WithScopeAccess<TableColumn>): string {
  return (
    '' + column.data.label + (column.data.formatField || column.data.field)
  );
}

function compress(columns: any) {
  const cols = {
    visible: columns.visible.map((c: any) => {
      const path =
        typeof c.data.field === 'function'
          ? c.data.name
          : c.data.formatField || c.data.field;
      const label = c.data.label;
      return [path, label];
    }),
    hidden: columns.hidden.map((c: any) => [
      c.data.formatField || c.data.field,
      c.data.label,
    ]),
  };
  return cols;
}

function isDefaultColumn(defaultCols: WithScopeAccess<TableColumn>[], path: string) {
  return defaultCols.find((dc) => {
    if (typeof dc.data.field === 'function') {
      return dc.data.name === path;
    } else {
      return dc.data.formatField === path || dc.data.field === path;
    }
  });
}

function existsInMapping(serviceMapping: ServiceMapping, path: string) {
  return serviceMapping.attrList?.some((attr: any) => attr.value === path);
}

function parseColumn(
  cols: any[],
  defaultCols: WithScopeAccess<TableColumn>[]
) {
  return cols.map((c: string) => {
    const dc = isDefaultColumn(defaultCols, c[0]);
    if (dc) {
      return dc;
    } else {
      return createDefaultColumn(c[0], c[1]);
    }
  });
}

function decompress(
  cols: any,
  defaultCols: WithScopeAccess<TableColumn>[]
): Columns {
  const columns: Columns = {
    visible: parseColumn(cols.visible, defaultCols),
    hidden: parseColumn(cols.hidden, defaultCols),
  };
  return columns;
}

export function saveColumnsToLocalStorage(obj: any, serviceId: string) {
  const columnsToSave = {
    [serviceId]: compress(obj)
  }
  saveCompressed(columnsToSave);
}

function saveCompressed(columnsToSave: any) {
  const statementsColumnsString = localStorage.getItem(localStorageColumnsName);
  if (statementsColumnsString) {
    try {
      let localStorageObj = JSON.parse(statementsColumnsString);
      localStorageObj = { ...localStorageObj, ...columnsToSave };
      localStorage.setItem(localStorageColumnsName, JSON.stringify(localStorageObj));
    } catch (e) {
      localStorage.removeItem(localStorageColumnsName);
      localStorage.setItem(localStorageColumnsName, JSON.stringify(columnsToSave));
    }
  } else {
    localStorage.setItem(localStorageColumnsName, JSON.stringify(columnsToSave));
  }
}

function stillActual(defaultCols: WithScopeAccess<TableColumn>[], serviceMapping: ServiceMapping, path: string) {
  const isDef = isDefaultColumn(defaultCols, path)
  return isDef || (!isDef && existsInMapping(serviceMapping, path));
}

function checkIfColumnHasBeenRemovedFromMapping(
  cols: any, defaultCols: WithScopeAccess<TableColumn>[], serviceMapping: ServiceMapping, serviceId: string
) {
  const filteredCols = {
    visible: cols.visible
      .filter((c: string[]) => stillActual(defaultCols, serviceMapping, c[0])),
    hidden: cols.hidden
      .filter((c: string[]) => stillActual(defaultCols, serviceMapping, c[0])),
  }
  if ((filteredCols.visible.length < cols.visible.length) || (filteredCols.hidden.length < cols.hidden.length)) {
    const columnsToSave = {
      [serviceId]: filteredCols
    }
    saveCompressed(columnsToSave);
  }
  return filteredCols;
}

export function getColumnsFromLocalStorage(serviceId: string, defaultCols: any, serviceMapping: ServiceMapping) {
  const statementsColumnsString = localStorage.getItem(localStorageColumnsName);
  if (statementsColumnsString) {
    try {
      const rowColumnsObj = JSON.parse(statementsColumnsString);
      if (rowColumnsObj[serviceId]) {
        const rowColumns = rowColumnsObj[serviceId];
        const filteredCols = checkIfColumnHasBeenRemovedFromMapping(rowColumns, defaultCols, serviceMapping, serviceId)
        return decompress(filteredCols, defaultCols);
      }
    } catch (e) {
      localStorage.removeItem(localStorageColumnsName);
    }
  }
  return {
    visible: cloneDeep(defaultCols),
    hidden: []
  };
}

export function removeColumnsFromLocalStorage(serviceId: string) {
  const statementsColumnsString = localStorage.getItem(localStorageColumnsName);
  if (statementsColumnsString) {
    try {
      const rowColumnsObj = JSON.parse(statementsColumnsString);
      if (rowColumnsObj[serviceId]) {
        delete rowColumnsObj[serviceId];
        if (isEmpty(rowColumnsObj)) {
          localStorage.removeItem(localStorageColumnsName);
        } else {
          localStorage.setItem(localStorageColumnsName, JSON.stringify(rowColumnsObj));
        }
      }
    } catch (e) {
      localStorage.removeItem(localStorageColumnsName);
    }
  }
}

export const defaultColumnsExtraFields: any = {
  'applicant.addressInfo.adressRegistration.fullAddress': {
    altNames: [
      'applicant.address.register.text',
      'statement.recipientPersonalData.appRegAddress',
      'applicant.addressInfo.adressStay.fullAddress'
    ]
  },
  'system.startDate': {
    type: ColumnTypeEnum.Date
  },
  'common.dueDate': {
    type: ColumnTypeEnum.Date
  },
  'common.finishDate': {
    type: ColumnTypeEnum.Date
  },
  'system.status.internal': {
    type: ColumnTypeEnum.Dictionary
  }
}

export function removeServiceIdFromQuery(query: string, serviceId: string): string {
  const serviceQueryEquation = `system.serviceId==${serviceId}`;
  const serviceInTheMiddleOrEnd = ` and ${serviceQueryEquation}`;
  const serviceInTheBeginning = `${serviceQueryEquation} and `;
  if (query === serviceQueryEquation) {
    return '';
  } else if (query.includes(serviceInTheMiddleOrEnd)) {
    return query.replace(serviceInTheMiddleOrEnd, '');
  } else if (query.startsWith(serviceInTheBeginning)) {
    return query.replace(serviceInTheBeginning, '')
  }
  return query;
}

export function fillBooleanValues(records: any, serviceMapping: ServiceMapping) {
  if (!serviceMapping || !serviceMapping.attrList) {
    return records;
  }

  const booleanColumns = serviceMapping.attrList
    .filter((attr: any) => attr.type === FieldType.Boolean);
  if (!records.length || !booleanColumns.length) {
    return records;
  }
  const filledRecords = records.map((r: any) => {
    booleanColumns.forEach((bc: any) => {
      const value = get(r, bc.value);
      let label;
      switch (value) {
        case true:
          label = i18n.t('base.yes');
          break;
        case false:
          label = i18n.t('base.no');
          break;
        default:
          label = '-';
      }
      set(r, bc.value, label);
    });
    return r;
  });
  return filledRecords;
}