import { CClient, HelpServer, Komand, KomandNaExport, Modul, SMessage, SRecord } from "../utils/types";
import { join } from "path";
import { existsSync, readFileSync, writeFileSync } from "fs";
import { oddiakritikovat, messageReply, strankovani } from "../utils/utils";
import { APIEmbed } from "discord.js";

let client: CClient;
const cesta = `${join(__dirname, "../../res/")}custom`;
const helpServer: HelpServer = require("../utils/helpServer");
let zakladniKomandy: SRecord<Komand>;
let zakladniAliasy: SRecord<string>;
let customKomandy: SRecord<{ text: string; owner: string; }>;
let customAliasy: SRecord<{ cmd: string; owner: string; }>;

function spojit() {
  const cKomandyAsKomand: SRecord<Komand> = {};
  const cKomandyForExport: KomandNaExport[] = [];

  for (const komand in customKomandy) {
    cKomandyAsKomand[komand] = { run: customKomandy[komand].text };
    cKomandyForExport.push({ name: komand, custom: true });
  }

  client.komandy = { ...cKomandyAsKomand, ...zakladniKomandy };

  helpServer.customKomandy = cKomandyForExport;

  const cAliasyForExport: SRecord<string> = {};

  for (const alias in customAliasy) {
    cAliasyForExport[alias] = customAliasy[alias].cmd;
  }

  client.aliasy = { ...zakladniAliasy, ...cAliasyForExport };
  helpServer.customAliasy = cAliasyForExport;
}

function save() {
  writeFileSync(`${cesta}Komandy.json`, JSON.stringify(customKomandy));
  writeFileSync(`${cesta}Aliasy.json`, JSON.stringify(customAliasy));
  spojit();
}

function komandNeboAlias(nazev: string) {
  if (customKomandy[nazev]) return { jeKomand: true, cmd: customKomandy[nazev] };
  if (customAliasy[nazev]) return { jeKomand: false, cmd: customAliasy[nazev] };
  return { jeKomand: false };
}

function zmrdovoAliasy(zacatek: string, owner: string, mes: SMessage) {
  const arr = [`${zacatek}:\n`];

  for (const key in customKomandy) {
    if (customKomandy[key].owner == owner) arr.push(key);
  }

  arr.push("\najilasy:\n");

  for (const key in customAliasy) {
    if (customAliasy[key].owner == owner) arr.push(key);
  }

  let text = "";
  arr.forEach(element => {
    if (text.length + element.length > 2000) {
      messageReply(mes, { content: text, allowedMentions: { users: [] } });
      text = "";
    }
    text += `${element}\n`;
  });

  messageReply(mes, { content: text, allowedMentions: { users: [] } });
}

const exp: Modul = {
  more_komandy: {
    naucse: {
      arg: "<název nového komandu> <text nového komandu>",
      run: (mes, arg) => {
        const args = arg.split(/\s/).filter(v => v != "");
        if (args.length == 0) return "a co se mam jako naucit";
        if (args.length == 1) return "a co bich nato mnel rict????";

        const name = oddiakritikovat(args[0].toLowerCase());
        if (zakladniKomandy[name] || customKomandy[name]) return "tuten komand uz ale egzistuje";
        if (zakladniAliasy[name] || customAliasy[name]) return "tuto uz je ale alijas";

        customKomandy[name] = { text: args.splice(1).join(" "), owner: mes.author.id };
        save();
        return "jo";
      }
    },

    naucsealias: {
      arg: "<název nového aliasu> <název existujícího komandu nebo aliasu>",
      als: ["naucsea"],
      run: (mes, arg) => {
        const args = arg.split(/\s/).filter(v => v != "").map(e => oddiakritikovat(e).toLowerCase());

        if (args.length == 0) return "a co se mam jako naucit";
        if (args.length == 1) return "a co to ma znamenat????";

        if (zakladniKomandy[args[0]] || customKomandy[args[0]]) return "tuto uz je ale komand";
        if (zakladniAliasy[args[0]] || customAliasy[args[0]]) return "tuto uz ale egzistuje";

        let jmeno: string;
        if (!zakladniKomandy[args[1]] && !zakladniAliasy[args[1]]) {
          if (!customKomandy[args[1]] && !customAliasy[args[1]]) return `nejze "${args[1]}" neni realnej ani vlastni komand ani alias`;
          jmeno = customKomandy[args[1]] ? args[1] : customAliasy[args[1]].cmd;
        } else jmeno = zakladniKomandy[args[1]] ? args[1] : zakladniAliasy[args[1]];

        if (args.length > 2) jmeno += " " + args.slice(2).join(" ");

        customAliasy[args[0]] = { cmd: jmeno, owner: mes.author.id };
        save();
        return "jo";
      }
    },

    zapomen: {
      arg: "název komandu nebo aliasu",
      run: (mes, arg) => {
        const name = oddiakritikovat(arg.toLowerCase());

        if (name == "") return "a co mam jako zapomenout";

        if (zakladniKomandy[name]) return "tuten komand se neda smazat ti smazko";
        if (zakladniAliasy[name]) return "tuten alijaas se neda smazat ti smazko";

        const { jeKomand, cmd } = komandNeboAlias(name);
        if (!cmd) return `"${name}" nen komnad an alias`;

        if (cmd.owner != mes.author.id) return "tuto ael neni tvoje toxikale zkurvenej";

        jeKomand ? delete customKomandy[name] : delete customAliasy[name];
        save();
        return "jo";
      }
    },

    kohoje: {
      arg: "název komandu nebo aliasu",
      run: (_, arg) => {
        const cmdName = oddiakritikovat(arg.toLowerCase());
        const cmd = customKomandy[cmdName] ?? customAliasy[cmdName];

        if (!cmd) return `"${cmdName}" nen vlastny komand an alijas`;

        return `vlastnitel je <@${cmd.owner}>`;
      }
    },

    mojekomandy: mes => {
      zmrdovoAliasy("tovje koamdy", mes.author.id, mes);
    },

    jehokomandy: {
      DMUnsafe: true,
      run: mes => {
        const kdo = mes.mentions.members?.first();

        if (!kdo) return "ael koho";

        zmrdovoAliasy(`koamdy kkta ${kdo.nickname}`, kdo.id, mes);
      }
    },

    uprav: {
      arg: "název komandu",
      run: (mes, arg) => {
        const args = arg.split(/\s/).filter(v => v != "");

        if (args.length == 0) return "a co mam jako vopravit";
        if (args.length == 1) return "a co bich nato mnel rict????";

        const name = oddiakritikovat(args[0].toLowerCase());

        if (zakladniKomandy[name]) return "tuten komand se neda vopravit";
        if (zakladniAliasy[name]) return "tuten alijaas se neda vopravit";

        const { jeKomand, cmd } = komandNeboAlias(name);
        if (!cmd) return `"${name}" nen komnad an alias`;

        if (cmd.owner != mes.author.id) return "tuto ael neni tvoe toxikale zkurvenej";

        jeKomand ? delete customKomandy[name] : delete customAliasy[name];

        customKomandy[name] = { text: args.splice(1).join(" "), owner: mes.author.id };
        save();
        return "jo";
      }
    },

    uprava: {
      arg: "název aliasu",
      run: (mes, arg) => {
        const args = arg.split(/\s/).filter(v => v != "").map(v => oddiakritikovat(v));
        const name = args[0];

        if (args.length == 0) return "a co mam jako vopravit";
        if (args.length == 1) return "a co to ma znamenat????";

        if (zakladniKomandy[name]) return "tuten komand se neda vopravit";
        if (zakladniAliasy[name]) return "tuten alijaas se neda vopravit";

        const { jeKomand, cmd } = komandNeboAlias(name);
        if (!cmd) return `"${name}" nen komnad an alias`;

        if (cmd.owner != mes.author.id) return "tuto ael neni tvoe toxikale zkurvenej";

        let jmeno: string;
        if (!zakladniKomandy[args[1]] && !zakladniAliasy[args[1]]) {
          if (!customKomandy[args[1]] && !customAliasy[args[1]]) return `nejze "${args[1]}" neni realnej ani vlastni komand ani alias`;
          jmeno = customKomandy[args[1]] ? args[1] : customAliasy[args[1]].cmd;
        } else jmeno = zakladniKomandy[args[1]] ? args[1] : zakladniAliasy[args[1]];

        jeKomand ? delete customKomandy[name] : delete customAliasy[name];

        customAliasy[args[0]] = { cmd: jmeno, owner: mes.author.id };
        save();
        return "jo";
      }
    },

    aliasy: {
      arg: "název komandu nebo jedno z aliasů",
      run: (mes, arg) => {
        const name = arg.toLowerCase();
        const cmdName = client.aliasy[name] ?? name;

        let celkovadylka = 0;
        const stranky: string[][] = [[]];
        let aktualniStranka = 0;
        for (const key in client.aliasy) {
          const val = client.aliasy[key];
          if (val != cmdName) continue;

          const dylka = key.length + 3;
          celkovadylka += dylka;
          if (celkovadylka > 1024 || stranky[aktualniStranka].length == 20) {
            aktualniStranka++;
            celkovadylka = dylka;
          }

          const stranka = stranky[aktualniStranka] ??= [];
          stranka.push(key);
        }

        if (!celkovadylka) return `"${name}" bud nen9 komand ani ajilas nebo nema ajilasi vubec`;

        const zacatekNazvu = `alijasy pro **${cmdName}**:`;
        const embed: APIEmbed = {
          color: 13697024,
          fields: [{ name: zacatekNazvu, value: `• ${stranky[0].join("\n• ")}` }]
        };

        if (stranky.length == 1) return { embeds: [embed] };

        embed.fields![0].name += ` (1/${stranky.length})`;

        strankovani(mes.channel, embed, zacatekNazvu, stranky);
      }
    },

    coje: {
      arg: "název komandu nebo aliasu",
      run: (_, arg) => {
        const nazev = oddiakritikovat(arg.toLowerCase());

        // Vestavěnej komand
        const vZakladni = zakladniKomandy[nazev]?.run;
        if (typeof vZakladni == "function") {
          let telo = vZakladni.toString();

          const odsazeni = /^( +)/m.exec(telo);
          if (odsazeni)
            telo = telo.replace(new RegExp(`^ \{${odsazeni[1].length - 4}\}`, "gm"), "");

          telo = telo.replace(/```/g, "`\u200b``");

          if (telo.length > 2000 - 42) {
            telo = telo.slice(0, 2000 - 43) + "…";
          }
          return "tuto je kmenovej koamnd a dela:\n```js\n" + telo + "\u200b```";
        }

        if (typeof vZakladni == "string")
          return `tuto je kmenovej koamnd a povida "${vZakladni}"`;

        // Vestavěnej alias
        const vZakladniAlias = zakladniAliasy[nazev];
        if (vZakladniAlias)
          return `tuto je kmenovej alijaas na "${vZakladniAlias}"`;

        // Vlastní komand
        const vlastniKomand = customKomandy[nazev];
        if (vlastniKomand) {
          const jekod = vlastniKomand.text.startsWith("dj:");
          const textZatim = `tuto je valstni koamnd <@${vlastniKomand.owner}> a ${jekod ? "tahle fukue" : "povida"}:\`\`\``;
          return `${textZatim}${vlastniKomand.text.slice(0, 1997 - textZatim.length)}\`\`\``;
        }

        // Vlastní alias
        const vlastniAlias = customAliasy[nazev];
        if (vlastniAlias)
          return `tuto je vlastni alijaas <@${vlastniAlias.owner}> na "${vlastniAlias.cmd}"`;

        return `${nazev} nic neeni`;
      }
    }
  },

  on_clientReady: () => {
    client = module.exports.client;
    zakladniKomandy = client.komandy;
    zakladniAliasy = client.aliasy;

    if (!existsSync(`${cesta}Komandy.json`)) customKomandy = {};
    else customKomandy = JSON.parse(readFileSync(`${cesta}Komandy.json`).toString());
    if (!existsSync(`${cesta}Aliasy.json`)) customAliasy = {};
    else customAliasy = JSON.parse(readFileSync(`${cesta}Aliasy.json`).toString());

    spojit();
  }
};

module.exports = exp;
