import * as fs from 'fs';

import stylesConfig from '../../styleNames';
import { emit } from '../../utils';
import { close as closeConfig } from '../../../index';
import parseConfig from '../parseConfig/parseConfig';

type Props = {
  config: Config;
  pathToSaveLocalConfig: string;
  pathToSaveDefaultConfig: string;
};

let shouldSaveDefaultConfig = false;

// собирает новый конфиг из HTML страницы и сохраняет его
const saveConfigEntry = ({
  config,
  pathToSaveLocalConfig,
  pathToSaveDefaultConfig,
}: Props): DynamicObject | undefined => {
  const configPage = config.HTML;
  let isConfigChanged = configPage.dataset.isChanged === 'true';

  if (isConfigChanged) {
    configPage.dataset.isChanged = 'false';

    const newConfig = saveConfigRecursion(
      configPage.getElementsByClassName(stylesConfig.highestNode)[0] as HTMLElement,
      config.default,
    );

    if (pathToSaveLocalConfig) {
      writeConfig(
        pathToSaveLocalConfig,
        newConfig,
        'не удалось перезаписать локальный конфиг',
      );
    }

    if (shouldSaveDefaultConfig) {
      writeConfig(
        pathToSaveDefaultConfig,
        config.default,
        'не удалось перезаписать дефолтный конфиг',
      );
    }

    isConfigChanged = false;

    config.parsed = parseConfig(newConfig);

    emit('saved', 'изменённый конфиг сохранён', config.parsed);

    closeConfig();

    return newConfig;
  } else {
    emit('info', 'нет изменений, чтобы их сохранить');

    closeConfig();
  }
};

const saveConfigRecursion = (parentNode: HTMLElement, defaultConfig?: DynamicObject) => {
  const configLayer = {} as DynamicObject;

  for (let i = 0; i < parentNode.children.length; i++) {
    const child = parentNode.children[i];
    const key = (child.children[0] as HTMLElement).dataset.key || '';
    const saveInDefault = (child.children[0] as HTMLElement).dataset.saveInDefault || '';

    if (child.classList.contains(stylesConfig.inputNode)) {
      configLayer[key] = {};
      configLayer[key].name = child.querySelector(
        `.${stylesConfig.nodeDescription} .${stylesConfig.nodeName}`,
      )?.textContent;

      const valueInput = child.querySelector('input');

      if (!valueInput) {
        const valueSelect = child.querySelector('select');
        if (valueSelect) {
          configLayer[key].value = Array.from(valueSelect.options).map((option) => {
            return {
              name: option.textContent,
              value: option.value,
              chosen: option.selected,
            };
          });
        }
      } else {
        switch (valueInput.type) {
          case 'checkbox': {
            configLayer[key].value = valueInput.checked;
            break;
          }
          case 'number': {
            configLayer[key].value = Number(valueInput.value);
            configLayer[key].type = valueInput.step.includes('.') ? 'float' : 'integer';
            configLayer[key].step = valueInput.step;
            break;
          }
          case 'text': {
            configLayer[key].value = valueInput.value;
            break;
          }
        }
      }

      if (typeof configLayer[key].value !== 'number' && configLayer[key].type) {
        delete configLayer[key].type;
      }
    } else if (child.classList.contains(stylesConfig.node)) {
      configLayer[key] = {
        name: child.children[0].getElementsByTagName('span')[0].textContent,
        value: saveConfigRecursion(
          child as HTMLElement,
          defaultConfig ? defaultConfig[key]?.value : undefined,
        ),
      };
    }

    if (defaultConfig && saveInDefault) {
      if (!defaultConfig[key]) {
        defaultConfig[key] = {};
      }

      shouldSaveDefaultConfig = true;
      if (saveInDefault.includes('name')) {
        defaultConfig[key].name = configLayer[key].name;
      }
      if (saveInDefault.includes('key')) {
        defaultConfig[key].key = configLayer[key].key;
      }
      if (saveInDefault.includes('value')) {
        defaultConfig[key].value = configLayer[key].value;
        if (configLayer[key].type) {
          defaultConfig[key].type = configLayer[key].type;
        }
        if (configLayer[key].step) {
          defaultConfig[key].step = configLayer[key].step;
        }
      }
    }
  }

  if (defaultConfig) {
    const keys = Object.keys(configLayer);
    const propsToDeleteInDefault = Object.keys(defaultConfig).filter(
      (key) => !keys.includes(key),
    );

    if (propsToDeleteInDefault.length > 0) {
      shouldSaveDefaultConfig = true;
      propsToDeleteInDefault.forEach((key) => delete defaultConfig[key]);
    }
  }

  return configLayer;
};

const writeConfig = (
  path: string,
  config: DynamicObject | undefined,
  emitMessage: string,
) => {
  try {
    fs.writeFileSync(path, JSON.stringify(config, null, '\t'));
  } catch (err) {
    console.error(err);
    emit('error', emitMessage);
  }
};

export default saveConfigEntry;
