import React from "react";
import { CorporateUser, User } from "@/interfaces/user";
import { BsBank, BsPersonFill } from "react-icons/bs";
import IconCard from "./IconCard";
import useAssignmentsCorporates from "@/hooks/useAssignmentCorporates";
import ReactDatePicker from "react-datepicker";
import moment from "moment";
import { Assignment, AssignmentWithCorporateId } from "@/interfaces/results";
import {
  CellContext,
  createColumnHelper,
  flexRender,
  getCoreRowModel,
  HeaderGroup,
  Table,
  useReactTable,
} from "@tanstack/react-table";
import Checkbox from "@/components/Low/Checkbox";

interface Props {
  corporateUsers: User[];
  users: User[];
}

interface TableData {
  user: string;
  correct: number;
  corporate: string;
  submitted: boolean;
  date: moment.Moment;
  assignment: string;
  corporateId: string;
}

interface UserCount {
  userCount: number;
  maxUserCount: number;
}

const MasterStatistical = (props: Props) => {
  const { users, corporateUsers } = props;

  const corporateRelevantUsers = React.useMemo(
    () => corporateUsers.filter((x) => x.type !== "student") as CorporateUser[],
    [corporateUsers]
  );

  const corporates = React.useMemo(
    () => corporateRelevantUsers.map((x) => x.id),
    [corporateRelevantUsers]
  );

  const [selectedCorporates, setSelectedCorporates] =
    React.useState<string[]>(corporates);
  const [startDate, setStartDate] = React.useState<Date | null>(
    moment("01/01/2023").toDate()
  );
  const [endDate, setEndDate] = React.useState<Date | null>(
    moment().endOf("year").toDate()
  );

  const { assignments } = useAssignmentsCorporates({
    // corporates: [...corporates, "tYU0HTiJdjMsS8SB7XJsUdMMP892"],
    corporates: selectedCorporates,
    startDate,
    endDate,
  });

  const tableResults = React.useMemo(
    () =>
      assignments.reduce((accmA: TableData[], a: AssignmentWithCorporateId) => {
        const userResults = a.assignees.map((assignee) => {
          const userStats =
            a.results.find((r) => r.user === assignee)?.stats || [];
          const userName = users.find((u) => u.id === assignee)?.name || "";
          const corporate = users.find((u) => u.id === a.assigner)?.name || "";
          const commonData = {
            user: userName,
            corporateId: a.corporateId,
            corporate,
            assignment: a.name,
          };
          if (userStats.length === 0) {
            return {
              ...commonData,
              correct: 0,
              submitted: false,
              // date: moment(),
            };
          }

          return {
            ...commonData,
            correct: userStats.reduce((n, e) => n + e.score.correct, 0),
            submitted: true,
            date: moment.max(userStats.map((e) => moment(e.date))),
          };
        }) as TableData[];

        return [...accmA, ...userResults];
      }, []),
    [assignments, users]
  );

  const getCorporateScores = (corporateId: string): UserCount => {
    const corporateAssignmentsUsers = assignments
      .filter((a) => a.corporateId === corporateId)
      .reduce((acc, a) => acc + a.assignees.length, 0);

    const corporateResults = tableResults.filter(
      (r) => r.corporateId === corporateId
    ).length;

    return {
      maxUserCount: corporateAssignmentsUsers,
      userCount: corporateResults,
    };
  };

  const corporateScores = corporates.reduce(
    (accm, id) => ({
      ...accm,
      [id]: getCorporateScores(id),
    }),
    {}
  ) as Record<string, UserCount>;

  const consolidateScore = Object.values(corporateScores).reduce(
    (acc: UserCount, { userCount, maxUserCount }: UserCount) => ({
      userCount: acc.userCount + userCount,
      maxUserCount: acc.maxUserCount + maxUserCount,
    }),
    { userCount: 0, maxUserCount: 0 }
  );

  const getConsolidateScoreStr = (data: UserCount) =>
    `${data.userCount}/${data.maxUserCount}`;

  const columnHelper = createColumnHelper<TableData>();

  const defaultColumns = [
    columnHelper.accessor("user", {
      header: "User",
      id: "user",
      cell: (info) => {
        return <span>{info.getValue()}</span>;
      },
    }),
    columnHelper.accessor("corporate", {
      header: "Corporate",
      id: "corporate",
      cell: (info) => {
        return <span>{info.getValue()}</span>;
      },
    }),
    columnHelper.accessor("assignment", {
      header: "Assignment",
      id: "assignment",
      cell: (info) => {
        return <span>{info.getValue()}</span>;
      },
    }),
    columnHelper.accessor("submitted", {
      header: "Submitted",
      id: "submitted",
      cell: (info) => {
        return (
          <Checkbox isChecked={info.getValue()} disabled onChange={() => {}}>
            <span></span>
          </Checkbox>
        );
      },
    }),
    columnHelper.accessor("correct", {
      header: "Correct",
      id: "correct",
      cell: (info) => {
        return <span>{info.getValue()}</span>;
      },
    }),
    columnHelper.accessor("date", {
      header: "Date",
      id: "date",
      cell: (info) => {
        const date = info.getValue();
        if (date) {
          return <span>{date.format("DD/MM/YYYY")}</span>;
        }

        return <span>{""}</span>;
      },
    }),
  ];

  const table = useReactTable({
    data: tableResults,
    columns: defaultColumns,
    getCoreRowModel: getCoreRowModel(),
  });

  const areAllSelected = selectedCorporates.length === corporates.length;

  const getStudentsConsolidateScore = () => {
    if (tableResults.length === 0) {
      return { highest: null, lowest: null };
    }

    // Find the student with the highest and lowest score
    return tableResults.reduce(
      (acc, curr) => {
        if (curr.correct > acc.highest.correct) {
          acc.highest = curr;
        }
        if (curr.correct < acc.lowest.correct) {
          acc.lowest = curr;
        }
        return acc;
      },
      { highest: tableResults[0], lowest: tableResults[0] }
    );
  };

  const consolidateResults = getStudentsConsolidateScore();
  return (
    <>
      <div className="flex flex-wrap gap-2 items-center text-center">
        <IconCard
          Icon={BsBank}
          label="Consolidate"
          value={getConsolidateScoreStr(consolidateScore)}
          color="purple"
          onClick={() => {
            if (areAllSelected) {
              setSelectedCorporates([]);
              return;
            }
            setSelectedCorporates(corporates);
          }}
          isSelected={areAllSelected}
        />
        {corporateRelevantUsers.map((group) => {
          const isSelected = selectedCorporates.includes(group.id);
          return (
            <IconCard
              key={group.id}
              Icon={BsBank}
              label={group.corporateInformation?.companyInformation?.name}
              value={getConsolidateScoreStr(corporateScores[group.id])}
              color="purple"
              onClick={() => {
                if (isSelected) {
                  setSelectedCorporates(
                    selectedCorporates.filter((x) => x !== group.id)
                  );
                  return;
                }
                setSelectedCorporates([...selectedCorporates, group.id]);
              }}
              isSelected={isSelected}
            />
          );
        })}
      </div>
      <div className="flex flex-col gap-3 w-full">
        <label className="font-normal text-base text-mti-gray-dim">Date</label>
        <ReactDatePicker
          dateFormat="dd/MM/yyyy"
          className="px-4 py-6 w-52 text-sm text-center font-normal placeholder:text-mti-gray-cool disabled:bg-mti-gray-platinum/40 disabled:text-mti-gray-dim disabled:cursor-not-allowed rounded-full border border-mti-gray-platinum focus:outline-none"
          selected={startDate}
          startDate={startDate}
          endDate={endDate}
          selectsRange
          showMonthDropdown
          onChange={([initialDate, finalDate]: [Date, Date]) => {
            setStartDate(initialDate ?? moment("01/01/2023").toDate());
            if (finalDate) {
              // basicly selecting a final day works as if I'm selecting the first
              // minute of that day. this way it covers the whole day
              setEndDate(moment(finalDate).endOf("day").toDate());
              return;
            }
            setEndDate(null);
          }}
        />
      </div>
      <div>
        <table className="rounded-xl h-full bg-mti-purple-ultralight/40 w-full">
          <thead>
            {table.getHeaderGroups().map((headerGroup) => (
              <tr key={headerGroup.id}>
                {headerGroup.headers.map((header) => (
                  <th className="p-4 text-left" key={header.id}>
                    {header.isPlaceholder
                      ? null
                      : flexRender(
                          header.column.columnDef.header,
                          header.getContext()
                        )}
                  </th>
                ))}
              </tr>
            ))}
          </thead>
          <tbody className="px-2">
            {table.getRowModel().rows.map((row) => (
              <tr
                className="odd:bg-white even:bg-mti-purple-ultralight/40 rounded-lg py-2"
                key={row.id}
              >
                {row.getVisibleCells().map((cell) => (
                  <td className="px-4 py-2" key={cell.id}>
                    {flexRender(cell.column.columnDef.cell, cell.getContext())}
                  </td>
                ))}
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      <div className="flex flex-wrap gap-2 items-center text-center">
        {consolidateResults.highest && (
          <IconCard
            onClick={() => {}}
            Icon={BsPersonFill}
            label={`Highest result: ${consolidateResults.highest.user}`}
            color="purple"
          />
        )}
        {consolidateResults.lowest && (
          <IconCard
            onClick={() => {}}
            Icon={BsPersonFill}
            label={`Lowest result: ${consolidateResults.lowest.user}`}
            color="purple"
          />
        )}
      </div>
    </>
  );
};

export default MasterStatistical;
