import { always, cond, equals, is, T,  mergeLeft } from "ramda";
import Handlebars from "handlebars/dist/cjs/handlebars";
import moment from "moment";
import presetConfig from './presetConfig'

const tablefy = (list = []) => {
  const defaultData = (title) => ({
    headerFilter: "input",
    minWidth: 80,
    headerFilterPlaceholder: title,
    download: false,
    print: false,
    vertAlign: "middle",
    sorter: "string",
    responsive: 0
  })

  if (!is(Array, list)) return []
  return list.map((el) => mergeLeft(el, defaultData(el?.title || "")))
}

const math = (value, operator, operand) => {
  var left = parseFloat(value);
  var right = parseFloat(operand);

  switch(operator) {
  case "+":
    return left + right;
  case "-":
    return left - right;
  case "*":
    return left * right;
  case "/":
    return left / right;
  case "%":
    return left % right;
  default:
    return "";
  }
}

const link = (col) => ({
  ...col,
  formatter: (cell, { prefix = "", text, key = "id" }, onRendered) => {
    onRendered(function () {
      let row = cell.getRow().getData();
      if (!text && !cell.getValue()) {
        return null;
      }
      if (!row[key]) return null;

      cell.getElement().innerHTML = `<a target="_blank" href="${prefix}/${
        row[key]
      }">${text || cell.getValue()}</a>`;
    });
  },
});

[
  ['math', math],
  ['presetConfig', (record, pack) => presetConfig(pack, record)],
  [
    "dt_shift",
    (date, shift, param) => {
      return date ? moment(date).add(shift, param) : "нд";
    },
  ],
  [
    "dt_format",
    (date) => {
      return date ? moment(date).format("DD.MM.YYYY HH:mm") : "нд";
    },
  ],
  [
    "dt_db_format",
    (date) => {
      return date ? moment(date).format("YYYY-MM-DDTHH:mm:ss") : "нд";
    },
  ],
  [
    "from_now",
    (date) => {
      return moment(date).fromNow()
    },
  ],
  [
    "json_parse",
    (item) => {
      return `
        <div>
          ${item}
        </div>
      `
    },
  ],
  [
    "time_from_sec",
    (ms) => {
      if (!ms) return "н/д"
      return `${moment(moment().subtract(Math.round(ms), 'milliseconds')).fromNow()}`.replace("назад", '')
    },
  ],
  [
    "lenght",
    (list) => {
      return is(Array, list) ? list.length : 0;
    },
  ],
  [
    "more",
    (one, two) => {
      return one > two;
    },
  ],
  [
    "less",
    (one, two) => {
      return one < two;
    },
  ],
  [
    "or",
    (one, two) => {
      return one || two;
    },
  ],
  [
    "eq",
    (one, two) => {
      return one === two;
    },
  ],
  [
    "endOf",
    (date, param) => moment(date).endOf(param)
  ],
  [
    "startOf",
    (date, param) => moment(date).startOf(param)
  ],
  [
    "render",
    (list, key) => {
      return list.map(el => el[key]).join(", ")
    }
  ],
  [
    "get",
    (map, key) => {
      return map[key] ? `${map[key]}` : ""
    }
  ],
  [
    "get_from",
    (map, key) => {
      return map[key] ? `${map[key]}` : ""
    }
  ],
  [
    "uint8parse",
    (list) => pipe(
      (x) => Uint8Array.from(x, e => e.charCodeAt(0)),
      Array.from
    )(list)
  ],
  [
    "filter_aoo",
    (list = [], key, _availible_list) => {
      const availible_list = pipe(
        (x) => Uint8Array.from(x, e => e.charCodeAt(0)),
        Array.from
      )(_availible_list)
      return list.filter((el) =>
        availible_list.includes(el[key]))
    }
  ]
].forEach(([name, func]) => {
  Handlebars.registerHelper(name, func);
});

const render = (col) => ({
  ...col,
  formatter: (cell, _, onRendered) => {
    onRendered(function () {
      if (`${col.render}`.includes("{{") && `${col.render}`.includes("}}")) {
        let record = cell.getRow().getData();
        cell.getElement().innerHTML = Handlebars.compile(col.render)(
          {...record, __record__: record}
        );
      } else if (typeof col.render === "function") {
        cell.getElement().innerHTML = col.render(cell.getRow().getData(), cell.getRow());
      }
    });
  },
});

let sorter = (a, b) => {
  let [a_field, b_field] = [a["field"], b["field"]];
  if (a_field.includes("id") && b_field.includes("id"))
    return a_field.localeCompare(b_field);
  if (a_field.includes("id")) return -1;
  if (b_field.includes("id")) return 1;
  if (a_field.includes("dt") && b_field.includes("dt"))
    return b_field.localeCompare(a_field);
  if (a_field.includes("dt")) return -1;
  if (b_field.includes("dt")) return 1;
  if (a_field.includes("imei") && b_field.includes("imei"))
    return b_field.localeCompare(a_field);
  if (a_field.includes("imei")) return -1;
  if (b_field.includes("imei")) return 1;
  return a_field.localeCompare(b_field);
};

const prepCol = (col) =>
  cond([
    [() => is(String, col.render), () => render(col)],
    [() => is(Function, col.render), () => render(col)],
    [equals("link"), () => link(col)],
    [T, always(col)],
  ])(col.mode);

const prepColumns = (cols) =>
  is(Array, cols) ? cols.map((col) => prepCol(col)) : [];

const renderGroupHeader = ({ groupHeader, value, count, group, extra }) => {
  const groupData = group._group;

  if (groupData.level == 0) {
    const {company_id, param, train_info: train, date: _date} = groupData.groupList[0].rows[0].data

    const date = `${_date}`.replace(/\s(.*)/gm, "")

    const icident_group = extra.find((el) =>
      el.date === date &&
      el.company_id == company_id &&
      el.train == train &&
      el.param == param
    ) || {}

    return Handlebars.compile(groupHeader)({
      _value: value,
      _count: count,
      extra: extra,
      icident_group: icident_group
    });
  }

  return `${value} (${count} записей)`;
};

const groupByFunction = (groupBy) => (data) =>
  Handlebars.compile(groupBy)(data);

const makedFiltering = (id, filterParams, selectedFilter, clearFilters) => {

  const table = document.querySelector(`#${id}`)
  const isFiltering = document.querySelector(`${id}-filters`)

  if(id && filterParams) {
    filterParams.unshift([])
    const filtersContainer = document.createElement('div')
    filtersContainer.setAttribute("id", `${id}-filters`)
    filtersContainer.classList.add("col-span-12")
    filtersContainer.innerHTML = `
      <div id="${id}-filtersContainer" class="filters flex flex-row items-center justify-start gap-3 mb-0 pt-2.5 bg-slate-100 rounded-t-md flex-row 2xl:flex-row">
        <div id="${id}-selectFilters" class="flex items-center justify-start gap-3 p-1 ml-2 text-base text-slate-700 font-bold">
          Фильтр по статусу
          <select name="selectFilter" id="${id}-selectFilter" class="flex text-gray-700 pl-3 pr-9 py-0.5 rounded cursor-pointer border-none" style="--tw-ring-color:focus: none" >
          ${filterParams.map((el) => {
    return (`<option value='${el}'>
                      ${el}
                    </option>`)
  })}
          </select>
        </div>
        <button id="${id}-filtersClear"class="w-fit h-fit flex items-center text-white text-sm font-bold bg-slate-600 hover:bg-slate-700 py-1 px-3 gap-1 rounded">Очистить фильтр</button>
      </div>`
    if(!isFiltering) {
      table.before(filtersContainer)
    }
    else {
      isFiltering.remove()
      table.before(filtersContainer)
    }

    const selectFilters = document.querySelectorAll(`#${id}-selectFilter`)
    const selectOptions = document.querySelectorAll(`#${id}-selectFilter option`)
    const buttonClearFilters = document.querySelector(`#${id}-filtersClear`)

    selectFilters.forEach((el) => {
      el.onchange = (e) => {
        if(e.target.value) {
          selectOptions[0].removeAttribute('selected')
          console.log('e', e)
          console.log('selectFilters[0]', selectFilters[0])
          console.log('selectOptions[0][0]', selectOptions[0])
          selectedFilter(e.target.value)
        } else {
          clearFilters()
          e.target.setAttribute('selected', 'selected')
        }
      }
    })

    buttonClearFilters.onclick = () => {
      clearFilters()
      selectOptions[0].setAttribute('selected', 'selected')
      console.log('selectFilters[0]', selectFilters[0])
    }
  }
}

const validation = (value, pagination) => {
  const pipe = (...fns) => (...x) => fns.reduce((error, validator) => error || validator(...x), undefined)

  const minPage = length => value => {
    value = value.replace(/\s+/g, '')
    return value >= length ? undefined : `Номер страницы должен быть больше или равен ${length}`
  }
  const maxPage = length => value => {
    value = value.replace(/\s+/g, '')
    return length >= value ? undefined : `Номер страницы должен быть меньше или равен ${length}`
  }
  const onlyDigits = value => {
    const pattern = /^([\d])*$/g
    return pattern.test(value) ? undefined : `Номер страницы должен содержать только цифры`
  }
  const composedValidators = pipe(onlyDigits, minPage(1), maxPage(pagination.total_pages))
  return composedValidators(value)
}

const pipe = (x) => (...fns) => fns.reduce((r, fn) => fn(r), x)

export {prepColumns, sorter, renderGroupHeader, groupByFunction, makedFiltering, tablefy, validation, pipe};
