import Handsontable from "handsontable"
import numbro from 'numbro';
import { textRenderer } from "handsontable/renderers"
import { TricksterInventory, TricksterItem } from "./trickster"
import Core from "handsontable/core";


export const BasicColumns = [
  "Image","Name","Count",
]

export const DetailsColumns = [
  "Desc","Use",
]

export const MoveColumns = [
  "MoveCount","Move",
]

export const TagColumns = [
  "All","Equip","Drill","Card","Quest","Consume", "Compound"
]

export const HackColumns = [
]

export const EquipmentColumns = [
  "MinLvl","Slots","RefineNumber","RefineState",
]

export const StatsColumns = [
  "AP","GunAP","AC","DX","MP","MA","MD","WT","DA","LK","HP","DP","HV",
]

export const ColumnNames = [
  ...BasicColumns,
  ...MoveColumns,
  ...DetailsColumns,
  ...EquipmentColumns,
  ...StatsColumns,
  ...TagColumns,
]

export type ColumnName = typeof ColumnNames[number]

const c = (a:ColumnName | ColumnInfo):ColumnName => {
  switch(typeof a) {
    case "string":
      return a
    case "object":
      return a.name
  }
}
export const LazyColumn = c;
export const ColumnSorter  = (a:ColumnName | ColumnInfo, b: ColumnName | ColumnInfo):number => {
  let n1 = ColumnNames.indexOf(c(a))
  let n2 = ColumnNames.indexOf(c(b))
  if(n1 == n2) {
    return 0
  }
  return n1 > n2 ? 1 : -1
}

export interface ColumnInfo  {
  name: ColumnName
  displayName:string
  renderer?:any
  filtering?:boolean
  writable?:boolean
  getter(item:TricksterItem):(string | number)
}

class Image implements ColumnInfo {
  name:ColumnName = 'Image'
  displayName = " "
  renderer = coverRenderer
  getter(item:TricksterItem):(string|number) {
    return item.image ? item.image : ""
  }
}

function coverRenderer(instance:any, td:any, row:any, col:any, prop:any, value:any, cellProperties:any) {
  const stringifiedValue = Handsontable.helper.stringify(value);
  if (stringifiedValue.startsWith('http')) {
    const img:any = document.createElement('IMG');
    img.src = value;
    Handsontable.dom.addEvent(img, 'mousedown', event =>{
      event!.preventDefault();
    });
    Handsontable.dom.empty(td);
    td.appendChild(img);
  } else {
  }
}

class Name implements ColumnInfo {
  name:ColumnName = "Name"
  displayName = "Name"
  filtering = true
  getter(item:TricksterItem):(string|number){
    return item.item_name
  }
}

class Count implements ColumnInfo {
  name:ColumnName = "Count"
  displayName = "Count"
  renderer = "numeric"
  filtering = true
  getter(item:TricksterItem):(string|number){
    return item.item_count
  }
}

class Move implements ColumnInfo {
  name:ColumnName = "Move"
  displayName = "Target"
  writable = true
  getter(item:TricksterItem):(string|number){
    return "-"
  }
}

class MoveCount implements ColumnInfo {
  name:ColumnName = "MoveCount"
  displayName = "Move #"
  renderer = moveCountRenderer
  writable = true
  getter(item:TricksterItem):(string|number){
    return ""
  }
}

function moveCountRenderer(instance:Core, td:any, row:number, col:number, prop:any, value:any, cellProperties:any) {
  let newValue = value;

  if (Handsontable.helper.isNumeric(newValue)) {
    const numericFormat = cellProperties.numericFormat;
    const cellCulture = numericFormat && numericFormat.culture || '-';
    const cellFormatPattern = numericFormat && numericFormat.pattern;
    const className = cellProperties.className || '';
    const classArr = className.length ? className.split(' ') : [];

    if (typeof cellCulture !== 'undefined' && !numbro.languages()[cellCulture]) {
      const shortTag:any = cellCulture.replace('-', '');
      const langData = (numbro as any)[shortTag];

      if (langData) {
        numbro.registerLanguage(langData);
      }
    }

    const totalCount = Number(instance.getCell(row,col-1)?.innerHTML)
    numbro.setLanguage(cellCulture);
    const num = numbro(newValue)
    if(totalCount < num.value()) {
      const newNum = numbro(totalCount)
      newValue = newNum.format(cellFormatPattern || '0');
    }else {
      newValue = num.format(cellFormatPattern || '0');
    }

    if (classArr.indexOf('htLeft') < 0 && classArr.indexOf('htCenter') < 0 &&
        classArr.indexOf('htRight') < 0 && classArr.indexOf('htJustify') < 0) {
      classArr.push('htRight');
    }

    if (classArr.indexOf('htNumeric') < 0) {
      classArr.push('htNumeric');
    }

    cellProperties.className = classArr.join(' ');

    td.dir = 'ltr';
    newValue = newValue + "x"
  }else {
    newValue = ""
  }
  textRenderer(instance, td, row, col, prop, newValue, cellProperties);

}

class Equip implements ColumnInfo {
  name:ColumnName = "Equip"
  displayName = "equip"
  getter(item:TricksterItem):(string|number){
    return item.is_equip ? 1 : 0
  }
}

class Drill implements ColumnInfo {
  name:ColumnName = "Drill"
  displayName = "drill"
  getter(item:TricksterItem):(string|number){
    return item.is_drill ? 1 : 0
  }
}

class All implements ColumnInfo {
  name:ColumnName = "All"
  displayName = "swap"
  getter(_:TricksterItem):(string|number){
    return -10000
  }
}

class Card implements ColumnInfo {
  name:ColumnName = "Card"
  displayName = "card"
  getter(item:TricksterItem):(string|number){
    return cardFilter(item) ? 1 : 0
  }
}

const cardFilter= (item:TricksterItem): boolean => {
  return (item.item_name.endsWith(" Card") || item.item_name.startsWith("Star Card"))
}
class Compound implements ColumnInfo {
  name:ColumnName = "Compound"
  displayName = "comp"
  getter(item:TricksterItem):(string|number){
    return compFilter(item) ? 1 : 0
  }
}

const compFilter= (item:TricksterItem): boolean => {
  return (item.item_desc.toLowerCase().includes("compound item"))
}



class Quest implements ColumnInfo {
  name:ColumnName = "Quest"
  displayName = "quest"
  getter(item:TricksterItem):(string|number){
    return questFilter(item) ? 1 : 0
  }
}

const questFilter= (item:TricksterItem): boolean => {
  return false
}

class Consume implements ColumnInfo {
  name:ColumnName = "Consume"
  displayName = "eat"
  getter(item:TricksterItem):(string|number){
    return consumeFilter(item) ? 1 : 0
  }
}

const consumeFilter= (item:TricksterItem): boolean => {
  const tl = item.item_use.toLowerCase()
  return tl.includes("recover") || tl.includes("restores")
}

class AP implements ColumnInfo {
  name:ColumnName = "AP"
  displayName = "AP"
  getter(item:TricksterItem):(string|number){
    return item.stats ? item.stats["AP"] : ""
  }
}

class GunAP implements ColumnInfo {
  name:ColumnName = "GunAP"
  displayName = "Gun AP"
  getter(item:TricksterItem):(string|number){
    return item.stats ? item.stats["Gun AP"] : ""
  }
}

class AC implements ColumnInfo {
  name:ColumnName = "AC"
  displayName = "AC"
  getter(item:TricksterItem):(string|number){
    return item.stats ? item.stats["AC"] : ""
  }
}

class DX implements ColumnInfo {
  name:ColumnName = "DX"
  displayName = "DX"
  getter(item:TricksterItem):(string|number){
    return item.stats ? item.stats["DX"] : ""
  }
}

class MP implements ColumnInfo {
  name:ColumnName = "MP"
  displayName = "MP"
  getter(item:TricksterItem):(string|number){
    return item.stats ? item.stats["MP"] : ""
  }
}

class MA implements ColumnInfo {
  name:ColumnName = "MA"
  displayName = "MA"
  getter(item:TricksterItem):(string|number){
    return item.stats ? item.stats["MA"] : ""
  }
}

class MD implements ColumnInfo {
  name:ColumnName = "MD"
  displayName = "MD"
  getter(item:TricksterItem):(string|number){
    return item.stats ? item.stats["MD"] : ""
  }
}

class WT implements ColumnInfo {
  name:ColumnName = "WT"
  displayName = "WT"
  getter(item:TricksterItem):(string|number){
    return item.stats ? item.stats["WT"] : ""
  }
}

class DA implements ColumnInfo {
  name:ColumnName = "DA"
  displayName = "DA"
  getter(item:TricksterItem):(string|number){
    return item.stats ? item.stats["DA"] : ""
  }
}

class LK implements ColumnInfo {
  name:ColumnName = "LK"
  displayName = "LK"
  getter(item:TricksterItem):(string|number){
    return item.stats ? item.stats["LK"] : ""
  }
}

class HP implements ColumnInfo {
  name:ColumnName = "HP"
  displayName = "HP"
  getter(item:TricksterItem):(string|number){
    return item.stats ? item.stats["HP"] : ""
  }
}

class DP implements ColumnInfo {
  name:ColumnName = "DP"
  displayName = "DP"
  getter(item:TricksterItem):(string|number){
    return item.stats ? item.stats["DP"] : ""
  }
}
class HV implements ColumnInfo {
  name:ColumnName = "HV"
  displayName = "HV"
  getter(item:TricksterItem):(string|number){
    return item.stats ? item.stats["HV"] : ""
  }
}

class MinLvl implements ColumnInfo {
  name:ColumnName = "MinLvl"
  displayName = "lvl"
  getter(item:TricksterItem):(string|number){
    //TODO:
    return item.item_min_level? item.item_min_level:""
  }
}

class Slots implements ColumnInfo {
  name:ColumnName = "Slots"
  displayName = "slots"
  getter(item:TricksterItem):(string|number){
    //TODO:
    return item.item_slots ? item.item_slots : ""
  }
}

class RefineNumber implements ColumnInfo {
  name:ColumnName = "RefineNumber"
  displayName = "refine"
  getter(item:TricksterItem):(string|number){
    return item.refine_level ? item.refine_level : 0
  }
}

class RefineState implements ColumnInfo {
  name:ColumnName = "RefineState"
  displayName = "bork"
  getter(item:TricksterItem):(string|number){
    return item.refine_state ? item.refine_state : 0
  }
}

class Desc implements ColumnInfo {
  name:ColumnName = "Desc"
  displayName = "desc"
  renderer = descRenderer
  getter(item:TricksterItem):(string|number){
    return item.item_desc
  }
}
function descRenderer(instance:any, td:any, row:any, col:any, prop:any, value:any, cellProperties:any) {
  const stringifiedValue = Handsontable.helper.stringify(value);
  let showText = stringifiedValue;
  const div= document.createElement('div');
  div.innerHTML = showText
  div.title = showText
  div.style.maxWidth = "30ch"
  div.style.textOverflow = "ellipsis"
  div.style.overflow=  "hidden"
  div.style.whiteSpace= "nowrap"
  Handsontable.dom.addEvent(div, 'mousedown', event =>{
    event!.preventDefault();
  });
  Handsontable.dom.empty(td);
  td.appendChild(div);
  td.classList.add("htLeft")
}

class Use implements ColumnInfo {
  name:ColumnName = "Use"
  displayName = "use"
  renderer= useRenderer;
  getter(item:TricksterItem):(string|number){
    return item.item_use
  }
}
function useRenderer(instance:any, td:any, row:any, col:any, prop:any, value:any, cellProperties:any) {
  const stringifiedValue = Handsontable.helper.stringify(value);
  let showText = stringifiedValue;
  const div= document.createElement('div');
  div.title = showText
  div.innerHTML = showText
  div.style.maxWidth = "30ch"
  div.style.textOverflow = "ellipsis"
  div.style.overflow=  "hidden"
  div.style.whiteSpace= "nowrap"
  Handsontable.dom.addEvent(div, 'mousedown', event =>{
    event!.preventDefault();
  });
  Handsontable.dom.empty(td);
  td.appendChild(div);
  td.classList.add("htLeft")
}





export const ColumnByNames = (...n:ColumnName[]) => {
  return n.map(ColumnByName)
}

export const ColumnByName = (n:ColumnName) => {
  return Columns[n]
}

export const Columns:{[Property in ColumnName]:ColumnInfo}= {
  Use: new Use(),
  Desc: new Desc(),
  Image: new           Image(),
  Name: new            Name(),
  Count: new           Count(),
  Move: new            Move(),
  MoveCount: new       MoveCount(),
  Equip: new           Equip(),
  Drill: new           Drill(),
  Card: new            Card(),
  Quest: new           Quest(),
  Consume: new         Consume(),
  AP: new              AP(),
  GunAP: new           GunAP(),
  AC: new              AC(),
  DX: new              DX(),
  MP: new              MP(),
  MA: new              MA(),
  MD: new              MD(),
  WT: new              WT(),
  DA: new              DA(),
  LK: new              LK(),
  HP: new              HP(),
  DP: new              DP(),
  HV: new              HV(),
  MinLvl: new          MinLvl(),
  Slots: new           Slots(),
  RefineNumber: new    RefineNumber(),
  RefineState: new     RefineState(),
  All: new All(),
  Compound: new Compound(),
}