import React from "react";

interface Conflicts {
  [index: string]: HTMLInputElement[];
}
interface ConflictsTmp {
  [index: string]: Set<string>;
}
interface IndexToElement {
  [index: string]: HTMLInputElement;
}

const indexToElement: IndexToElement = {};
const conflicts: Conflicts = {};
const marks: (HTMLInputElement | null)[][] = [];

const Timetable = ({ user }) => {
  const [editable, setEditable] = React.useState(true);
  const ref = React.useRef();

  const handleSelect = async (event: Event) => {
    const target: HTMLInputElement = event.target;
    console.log("select", target.name, target.checked);

    const changedInputs: any = [];
    // find whether there are checked input in conflict
    for (const input of conflicts[target.name]) {
      if (input.name === target.name) continue;
      if (input.checked) {
        alert("Error: Conflict select");
        location.reload();
        return
      }
    }
    for (const input of conflicts[target.name]) {
      if (input.name === target.name) continue;
      if (target.checked) {
        if (input.getAttribute("disabled") === null) {
          input.setAttribute("disabled", "true");
          changedInputs.push({ input, disable: false });
        }
      } else {
        if (input.getAttribute("disabled") === "true") {
          input.removeAttribute("disabled");
          changedInputs.push({ input, disable: true });
        }
      }
    }
    // post request
    const resp = await fetch("/api/record", {
      method: "POST",
      headers: { "Content-Type": "appliction/json" },
      body: JSON.stringify({
        name: target.name,
        checked: target.checked,
        user,
      }),
    });
    if (!resp.ok) {
      const json = await resp.json();
      alert(json.error);
      // revert conflict changed input
      for (const { input, disable } of changedInputs) {
        if (disable) {
          input.addAttribute("disabled", "true");
        } else {
          input.removeAttribute("disabled");
        }
      }
    }
  };

  const handleInput = (event: React.ChangeEvent<HTMLInputElement>): boolean => {
    const { target } = event;
    // validate
    if (target?.children[0]?.tagName !== "TABLE") {
      console.log("not a table");
      return false;
    }

    console.log(target.innerHTML);

    // turn off editable
    setEditable(false);

    const table = target.children[0];
    table.setAttribute("border", "1");

    // mark cell
    const conflictsTmp: ConflictsTmp = {};
    const tbody = table.children[table.children.length - 1];
    for (const tr_index in tbody.children) {
      const tr = tbody.children[tr_index];
      const row: (HTMLInputElement | null)[] = [];
      for (const td_index in tr.children) {
        const td = tr.children[td_index];
        if (td.tagName !== "TD") continue;
        if (td.getAttribute("bgcolor")?.toUpperCase() !== "#39CEFF") {
          row.push(null);
          continue;
        }

        const index = `${tr_index},${td_index}`;

        const placeholders = td.textContent?.trim().split(",");
        if (placeholders === undefined) continue;
        if (conflictsTmp[index] === undefined) conflictsTmp[index] = new Set();
        for (const ph of placeholders) conflictsTmp[index].add(ph);

        // mount click event
        const input = document.createElement("input");
        input.setAttribute("type", "checkbox");
        input.onchange = handleSelect;
        input.name = index;
        td.innerHTML = "";
        td.appendChild(input);
        indexToElement[index] = input;

        row.push(input);
      }
      marks.push(row);
    }

    // resolve conflicts
    for (const index in conflictsTmp) {
      if (conflicts[index] === undefined) conflicts[index] = [];
      for (const ph of Array.from(conflictsTmp[index])) {
        for (const conflictIndex in conflictsTmp) {
          if (conflictsTmp[conflictIndex].has(ph))
            conflicts[index].push(indexToElement[conflictIndex]);
        }
      }
    }

    console.log(conflicts);

    return true;
  };

  const refresh = async () => {
    const resp = await fetch(`/api/record?name=${user}`);
    const json = await resp.json();
    const occupied: string[] = json.occupied;
    const myselect: string[] = json.myselect;
    console.log(json);
    for (const index in indexToElement) {
      if (occupied.includes(index)) {
        indexToElement[index].style.display = "none";
      } else {
        indexToElement[index].style.display = "";
      }
      indexToElement[index].checked = myselect.includes(index);
    }
  };
  React.useEffect(() => {
    const interval = setInterval(() => {
      refresh();
    }, 1000);
    return () => {
      clearInterval(interval);
    };
  });

  React.useEffect(() => {
    fetch("/api/html")
      .then((resp) => resp.json())
      .then((json) => {
        console.log(ref);
        ref.current.innerHTML = json.html;
      })
      .then(() => {
        handleInput({ target: ref.current });
        refresh();
      });
  }, []);

  return (
    <>
      <button onClick={refresh}>Test</button>
      <span>Login as {user}</span>
      <div
        ref={ref}
        contentEditable={editable}
        style={{
          overflow: "scroll",
        }}
        onInput={handleInput}
      ></div>
    </>
  );
};

export default Timetable;
