/* eslint-disable @next/next/no-img-element */
import CardList from "@/components/High/CardList";
import Select from "@/components/Low/Select";
import Input from "@/components/Low/Input";
import Checkbox from "@/components/Low/Checkbox";
import Tooltip from "@/components/Low/Tooltip";
import { useEntityPermission } from "@/hooks/useEntityPermissions";
import { EntityWithRoles, Role } from "@/interfaces/entity";
import { User } from "@/interfaces/user";
import { sessionOptions } from "@/lib/session";
import { USER_TYPE_LABELS } from "@/resources/user";
import { findBy, mapBy, redirect, serialize } from "@/utils";
import { getEntityWithRoles } from "@/utils/entities.be";
import { shouldRedirectHome } from "@/utils/navigation.disabled";
import { doesEntityAllow } from "@/utils/permissions";
import { getUserName, isAdmin } from "@/utils/users";
import {
  filterAllowedUsers,
  getEntitiesUsers,
  getEntityUsers,
  getUsers,
} from "@/utils/users.be";
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
import axios from "axios";
import clsx from "clsx";
import { withIronSessionSsr } from "iron-session/next";
import moment from "moment";
import Head from "next/head";
import Link from "next/link";
import { useRouter } from "next/router";
import { Divider } from "primereact/divider";
import { useEffect, useState } from "react";
import ReactDatePicker from "react-datepicker";
import { CURRENCIES } from "@/resources/paypal";

import {
  BsCheck,
  BsChevronLeft,
  BsClockFill,
  BsEnvelopeFill,
  BsHash,
  BsPerson,
  BsPlus,
  BsStopwatchFill,
  BsTag,
  BsTrash,
  BsX,
} from "react-icons/bs";
import { toast } from "react-toastify";
import entities from "../../api/entities";

const expirationDateColor = (date: Date) => {
  const momentDate = moment(date);
  const today = moment(new Date());

  if (today.add(1, "days").isAfter(momentDate))
    return "!bg-mti-red-ultralight border-mti-red-light";
  if (today.add(3, "days").isAfter(momentDate))
    return "!bg-mti-rose-ultralight border-mti-rose-light";
  if (today.add(7, "days").isAfter(momentDate))
    return "!bg-mti-orange-ultralight border-mti-orange-light";
};

const CURRENCIES_OPTIONS = CURRENCIES.map(({ label, currency }) => ({
  value: currency,
  label,
}));

const USER_DATA_SCHEMA = {
  _id: 0,
  id: 1,
  name: 1,
  type: 1,
  profilePicture: 1,
  email: 1,
  lastLogin: 1,
  subscriptionExpirationDate: 1,
  entities: 1,
  corporateInformation: 1,
};

export const getServerSideProps = withIronSessionSsr(
  async ({ req, params }) => {
    const user = req.session.user as User;

    if (!user) return redirect("/login");
    if (shouldRedirectHome(user)) return redirect("/");

    const { id } = params as { id: string };

    const entity = await getEntityWithRoles(id);
    if (!entity) return redirect("/entities");

    if (!doesEntityAllow(user, entity, "view_entities"))
      return redirect(`/entities`);
    const [linkedUsers, entityUsers] = await Promise.all([
      isAdmin(user)
        ? getUsers({}, 0, {}, USER_DATA_SCHEMA)
        : getEntitiesUsers(
            mapBy(user.entities, "id"),
            {
              $and: [
                { type: { $ne: "developer" } },
                { type: { $ne: "admin" } },
              ],
            },
            0,
            USER_DATA_SCHEMA
          ),
      isAdmin(user)
        ? getEntityUsers(
            id,
            0,
            {
              id: { $ne: user.id },
            },
            USER_DATA_SCHEMA
          )
        : filterAllowedUsers(user, [entity], USER_DATA_SCHEMA),
    ]);

    const usersWithRole = entityUsers.map((u) => {
      const e = u?.entities?.find((e) => e.id === id);
      return { ...u, role: findBy(entity.roles, "id", e?.role) };
    });

    return {
      props: serialize({
        user,
        entity,
        users: usersWithRole,
        linkedUsers: linkedUsers.filter(
          (x) => !mapBy(entityUsers, "id").includes(x.id)
        ),
      }),
    };
  },
  sessionOptions
);

type UserWithRole = User & { role?: Role };

interface Props {
  user: User;
  entity: EntityWithRoles;
  users: UserWithRole[];
  linkedUsers: User[];
}

export default function Home({ user, entity, users, linkedUsers }: Props) {
  const [isAdding, setIsAdding] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [selectedUsers, setSelectedUsers] = useState<string[]>([]);
  const [expiryDate, setExpiryDate] = useState(entity?.expiryDate);
  const [paymentPrice, setPaymentPrice] = useState(entity?.payment?.price);
  const [paymentCurrency, setPaymentCurrency] = useState(
    entity?.payment?.currency
  );

  const router = useRouter();

  const canRenameEntity = useEntityPermission(user, entity, "rename_entity");
  const canViewRoles = useEntityPermission(user, entity, "view_entity_roles");
  const canDeleteEntity = useEntityPermission(user, entity, "delete_entity");

  const canAddMembers = useEntityPermission(user, entity, "add_to_entity");
  const canRemoveMembers = useEntityPermission(
    user,
    entity,
    "remove_from_entity"
  );

  const canAssignRole = useEntityPermission(user, entity, "assign_to_role");
  const canPay = useEntityPermission(user, entity, "pay_entity");

  const toggleUser = (u: User) =>
    setSelectedUsers((prev) =>
      prev.includes(u.id) ? prev.filter((p) => p !== u.id) : [...prev, u.id]
    );

  const removeParticipants = () => {
    if (selectedUsers.length === 0) return;
    if (!canRemoveMembers) return;
    if (
      !confirm(
        `Are you sure you want to remove ${selectedUsers.length} member${
          selectedUsers.length === 1 ? "" : "s"
        } from this entity?`
      )
    )
      return;

    setIsLoading(true);

    axios
      .patch(`/api/entities/${entity.id}/users`, {
        add: false,
        members: selectedUsers,
      })
      .then(() => {
        toast.success("The entity has been updated successfully!");
        router.replace(router.asPath);
        setSelectedUsers([]);
      })
      .catch((e) => {
        console.error(e);
        toast.error("Something went wrong!");
      })
      .finally(() => setIsLoading(false));
  };

  const addParticipants = () => {
    if (selectedUsers.length === 0) return;
    if (!canAddMembers || !isAdding) return;
    if (
      !confirm(
        `Are you sure you want to add ${selectedUsers.length} member${
          selectedUsers.length === 1 ? "" : "s"
        } to this entity?`
      )
    )
      return;

    setIsLoading(true);
    const defaultRole = findBy(entity.roles, "isDefault", true)!;

    axios
      .patch(`/api/entities/${entity.id}/users`, {
        add: true,
        members: selectedUsers,
        role: defaultRole.id,
      })
      .then(() => {
        toast.success("The entity has been updated successfully!");
        router.replace(router.asPath);
        setIsAdding(false);
      })
      .catch((e) => {
        console.error(e);
        toast.error("Something went wrong!");
      })
      .finally(() => setIsLoading(false));
  };

  const renameGroup = () => {
    if (!canRenameEntity) return;

    const label = prompt("Rename this entity:", entity.label);
    if (!label) return;

    setIsLoading(true);
    axios
      .patch(`/api/entities/${entity.id}`, { label })
      .then(() => {
        toast.success("The entity has been updated successfully!");
        router.replace(router.asPath);
      })
      .catch((e) => {
        console.error(e);
        toast.error("Something went wrong!");
      })
      .finally(() => setIsLoading(false));
  };

  const updateExpiryDate = () => {
    if (!isAdmin(user)) return;

    setIsLoading(true);
    axios
      .patch(`/api/entities/${entity.id}`, { expiryDate })
      .then(() => {
        toast.success("The entity has been updated successfully!");
        router.replace(router.asPath);
      })
      .catch((e) => {
        console.error(e);
        toast.error("Something went wrong!");
      })
      .finally(() => setIsLoading(false));
  };

  const updatePayment = () => {
    if (!isAdmin(user)) return;

    setIsLoading(true);
    axios
      .patch(`/api/entities/${entity.id}`, {
        payment: { price: paymentPrice, currency: paymentCurrency },
      })
      .then(() => {
        toast.success("The entity has been updated successfully!");
        router.replace(router.asPath);
      })
      .catch((e) => {
        console.error(e);
        toast.error("Something went wrong!");
      })
      .finally(() => setIsLoading(false));
  };

  const editLicenses = () => {
    if (!isAdmin(user)) return;

    const licenses = prompt(
      "Update the number of licenses:",
      (entity.licenses || 0).toString()
    );
    if (!licenses) return;
    if (!parseInt(licenses) || parseInt(licenses) <= 0)
      return toast.error("Write a valid number of licenses!");

    setIsLoading(true);
    axios
      .patch(`/api/entities/${entity.id}`, { licenses })
      .then(() => {
        toast.success("The entity has been updated successfully!");
        router.replace(router.asPath);
      })
      .catch((e) => {
        console.error(e);
        toast.error("Something went wrong!");
      })
      .finally(() => setIsLoading(false));
  };

  const deleteGroup = () => {
    if (!canDeleteEntity) return;
    if (!confirm("Are you sure you want to delete this entity?")) return;

    setIsLoading(true);

    axios
      .delete(`/api/entities/${entity.id}`)
      .then(() => {
        toast.success("This entity has been successfully deleted!");
        router.replace("/entities");
      })
      .catch((e) => {
        console.error(e);
        toast.error("Something went wrong!");
      })
      .finally(() => setIsLoading(false));
  };

  const assignUsersToRole = (role: string) => {
    if (!canAssignRole) return;
    if (selectedUsers.length === 0) return;

    setIsLoading(true);
    axios
      .post(`/api/roles/${role}/users`, { users: selectedUsers })
      .then(() => {
        toast.success("The role has been assigned successfully!");
        router.replace(router.asPath);
      })
      .catch((e) => {
        console.error(e);
        toast.error("Something went wrong!");
      })
      .finally(() => setIsLoading(false));
  };

  const renderCard = (u: UserWithRole) => {
    return (
      <button
        onClick={() => toggleUser(u)}
        disabled={isAdding ? !canAddMembers : !canRemoveMembers}
        key={u.id}
        className={clsx(
          "p-4 pr-6 h-48 relative border rounded-xl flex flex-col gap-3 justify-between text-left cursor-pointer",
          "hover:border-mti-purple transition ease-in-out duration-300",
          selectedUsers.includes(u.id) && "border-mti-purple"
        )}
      >
        <div className="flex items-center gap-2">
          <div className="min-w-[3rem] min-h-[3rem] w-12 h-12 border flex items-center justify-center overflow-hidden rounded-full">
            <img src={u.profilePicture} alt={u.name} />
          </div>
          <div className="flex flex-col">
            <span className="font-semibold">{getUserName(u)}</span>

            <span className="opacity-80 text-sm">
              {USER_TYPE_LABELS[u.type]} {u.role && `- ${u.role.label}`}
            </span>
          </div>
        </div>

        <div className="flex flex-col gap-1">
          <span className="flex items-center gap-2">
            <Tooltip tooltip="E-mail address">
              <BsEnvelopeFill />
            </Tooltip>
            {u.email}
          </span>
          <span className="flex items-center gap-2">
            <Tooltip tooltip="Expiration Date">
              <BsStopwatchFill />
            </Tooltip>
            {u.subscriptionExpirationDate
              ? moment(u.subscriptionExpirationDate).format("DD/MM/YYYY")
              : "Unlimited"}
          </span>
          <span className="flex items-center gap-2">
            <Tooltip tooltip="Last Login">
              <BsClockFill />
            </Tooltip>
            {u.lastLogin
              ? moment(u.lastLogin).format("DD/MM/YYYY - HH:mm")
              : "N/A"}
          </span>
        </div>
      </button>
    );
  };

  useEffect(() => setSelectedUsers([]), [isAdding]);

  return (
    <>
      <Head>
        <title>{entity.label} | EnCoach</title>
        <meta
          name="description"
          content="A training platform for the IELTS exam provided by the Muscat Training Institute and developed by eCrop."
        />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <>
        <section className="flex flex-col gap-0">
          <div className="flex flex-col gap-3">
            <div className="flex items-start justify-between">
              <div className="flex items-center gap-2">
                <Link
                  href="/entities"
                  className="text-mti-purple hover:text-mti-purple-dark transition ease-in-out duration-300 text-xl"
                >
                  <BsChevronLeft />
                </Link>
                <h2 className="font-bold text-2xl">
                  {entity.label}{" "}
                  {isAdmin(user) && `- ${entity.licenses || 0} licenses`}
                </h2>
              </div>

              {!isAdmin(user) && canPay && (
                <Link
                  href="/payment"
                  className={clsx(
                    "p-2 w-full max-w-[200px] flex justify-center text-sm font-normal rounded-full border focus:outline-none cursor-pointer",
                    "transition duration-300 ease-in-out",
                    !entity.expiryDate
                      ? "!bg-mti-green-ultralight !border-mti-green-light"
                      : expirationDateColor(entity.expiryDate),
                    "bg-white border-mti-gray-platinum"
                  )}
                >
                  {!entity.expiryDate && "Unlimited"}
                  {entity.expiryDate &&
                    moment(entity.expiryDate).format("DD/MM/YYYY")}
                </Link>
              )}
            </div>
            <div className="flex items-center gap-2">
              <button
                onClick={renameGroup}
                disabled={isLoading || !canRenameEntity}
                className="flex items-center gap-1 px-2 py-2 border rounded-full hover:bg-neutral-100 disabled:hover:bg-transparent disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer transition ease-in-out duration-300"
              >
                <BsTag />
                <span className="text-xs">Rename Entity</span>
              </button>
              {isAdmin(user) && (
                <button
                  onClick={editLicenses}
                  disabled={isLoading || !isAdmin(user)}
                  className="flex items-center gap-1 px-2 py-2 border rounded-full hover:bg-neutral-100 disabled:hover:bg-transparent disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer transition ease-in-out duration-300"
                >
                  <BsHash />
                  <span className="text-xs">Edit Licenses</span>
                </button>
              )}
              <button
                onClick={() => router.push(`/entities/${entity.id}/roles`)}
                disabled={isLoading || !canViewRoles}
                className="flex items-center gap-1 px-2 py-2 border rounded-full hover:bg-neutral-100 disabled:hover:bg-transparent disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer transition ease-in-out duration-300"
              >
                <BsPerson />
                <span className="text-xs">Edit Roles</span>
              </button>
              <button
                onClick={deleteGroup}
                disabled={isLoading || !canDeleteEntity}
                className="flex items-center gap-1 px-2 py-2 border border-mti-rose rounded-full bg-mti-rose-light text-white hover:bg-mti-rose-dark disabled:hover:bg-mti-rose-light disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer transition ease-in-out duration-300"
              >
                <BsTrash />
                <span className="text-xs">Delete Entity</span>
              </button>
            </div>
          </div>

          {isAdmin(user) && (
            <>
              <Divider />

              <div className="w-full flex justify-between items-center">
                <div className="flex items-center gap-4 w-full">
                  {!!expiryDate && (
                    <ReactDatePicker
                      className={clsx(
                        "p-2 w-full max-w-[200px] flex justify-center text-sm font-normal rounded-full border focus:outline-none cursor-pointer",
                        "hover:border-mti-purple tooltip",
                        !expiryDate
                          ? "!bg-mti-green-ultralight !border-mti-green-light"
                          : expirationDateColor(expiryDate),
                        "transition duration-300 ease-in-out"
                      )}
                      filterDate={(date) => moment(date).isAfter(new Date())}
                      dateFormat="dd/MM/yyyy"
                      selected={expiryDate ? moment(expiryDate).toDate() : null}
                      onChange={(date) => setExpiryDate(date)}
                    />
                  )}

                  {!expiryDate && (
                    <div
                      className={clsx(
                        "p-2 w-full max-w-[200px] flex justify-center text-sm font-normal rounded-full border focus:outline-none cursor-pointer",
                        "transition duration-300 ease-in-out",
                        !expiryDate
                          ? "!bg-mti-green-ultralight !border-mti-green-light"
                          : expirationDateColor(expiryDate),
                        "bg-white border-mti-gray-platinum"
                      )}
                    >
                      Unlimited
                    </div>
                  )}

                  <Checkbox
                    isChecked={!!expiryDate}
                    onChange={(checked: boolean) =>
                      setExpiryDate(
                        checked ? entity.expiryDate || new Date() : null
                      )
                    }
                  >
                    Enable expiry date
                  </Checkbox>
                </div>

                <button
                  onClick={updateExpiryDate}
                  disabled={expiryDate === entity.expiryDate}
                  className="flex w-fit text-nowrap items-center gap-1 px-2 py-2 border rounded-full border-mti-green bg-mti-green-light text-white hover:bg-mti-green-dark disabled:hover:bg-mti-green-light disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer transition ease-in-out duration-300"
                >
                  <BsCheck />
                  <span className="text-xs">Apply Change</span>
                </button>
              </div>

              <Divider />

              <div className="w-full flex items-center justify-between gap-8">
                <div className="w-full max-w-xl flex items-center gap-4">
                  <Input
                    name="paymentValue"
                    onChange={(e) =>
                      setPaymentPrice(e ? parseInt(e) : undefined)
                    }
                    type="number"
                    defaultValue={entity.payment?.price || 0}
                    thin
                  />
                  <Select
                    className={clsx(
                      "px-4 !py-2 !w-full text-sm font-normal placeholder:text-mti-gray-cool bg-white rounded-full border border-mti-gray-platinum focus:outline-none"
                    )}
                    options={CURRENCIES_OPTIONS}
                    value={CURRENCIES_OPTIONS.find(
                      (c) => c.value === paymentCurrency
                    )}
                    onChange={(value) =>
                      setPaymentCurrency(value?.value ?? undefined)
                    }
                  />
                </div>

                <button
                  onClick={updatePayment}
                  disabled={
                    !paymentPrice || paymentPrice <= 0 || !paymentCurrency
                  }
                  className="flex w-fit text-nowrap items-center gap-1 px-2 py-2 border rounded-full border-mti-green bg-mti-green-light text-white hover:bg-mti-green-dark disabled:hover:bg-mti-green-light disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer transition ease-in-out duration-300"
                >
                  <BsCheck />
                  <span className="text-xs">Apply Change</span>
                </button>
              </div>
            </>
          )}

          <Divider />
          <div className="flex items-center justify-between mb-4">
            <span className="font-semibold text-xl">
              Members ({users.length})
            </span>
            {!isAdding && (
              <div className="flex items-center gap-2">
                <button
                  onClick={() => setIsAdding(true)}
                  disabled={isLoading || !canAddMembers}
                  className="flex items-center gap-1 px-2 py-2 border rounded-full hover:bg-neutral-100 disabled:hover:bg-transparent disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer transition ease-in-out duration-300"
                >
                  <BsPlus />
                  <span className="text-xs">Add Members</span>
                </button>

                <Menu>
                  <MenuButton
                    disabled={
                      isLoading || !canAssignRole || selectedUsers.length === 0
                    }
                    className="flex items-center gap-1 px-2 py-2 border rounded-full hover:bg-neutral-100 disabled:hover:bg-transparent disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer transition ease-in-out duration-300"
                  >
                    <BsPerson />
                    <span className="text-xs">Assign Role</span>
                  </MenuButton>
                  <MenuItems
                    anchor="bottom"
                    className="bg-white rounded-xl shadow drop-shadow border mt-1 flex flex-col"
                  >
                    {entity.roles.map((role) => (
                      <MenuItem key={role.id}>
                        <button
                          onClick={() => assignUsersToRole(role.id)}
                          className="p-4 hover:bg-neutral-100 w-32"
                        >
                          {role.label}
                        </button>
                      </MenuItem>
                    ))}
                  </MenuItems>
                </Menu>

                <button
                  onClick={removeParticipants}
                  disabled={
                    selectedUsers.length === 0 || isLoading || !canRemoveMembers
                  }
                  className="flex items-center gap-1 px-2 py-2 border border-mti-rose rounded-full bg-mti-rose-light text-white hover:bg-mti-rose-dark disabled:hover:bg-mti-rose-light disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer transition ease-in-out duration-300"
                >
                  <BsTrash />
                  <span className="text-xs">Remove Members</span>
                </button>
              </div>
            )}
            {isAdding && (
              <div className="flex items-center gap-2">
                <button
                  onClick={() => setIsAdding(false)}
                  disabled={isLoading}
                  className="flex items-center gap-1 px-2 py-2 border rounded-full border-mti-rose bg-mti-rose-light text-white hover:bg-mti-rose-dark disabled:hover:bg-mti-rose-light disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer transition ease-in-out duration-300"
                >
                  <BsX />
                  <span className="text-xs">Discard Selection</span>
                </button>
                <button
                  onClick={addParticipants}
                  disabled={
                    selectedUsers.length === 0 || isLoading || !canAddMembers
                  }
                  className="flex items-center gap-1 px-2 py-2 border rounded-full border-mti-green bg-mti-green-light text-white hover:bg-mti-green-dark disabled:hover:bg-mti-green-light disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer transition ease-in-out duration-300"
                >
                  <BsPlus />
                  <span className="text-xs">
                    Add Members ({selectedUsers.length})
                  </span>
                </button>
              </div>
            )}
          </div>

          <CardList<User | UserWithRole>
            list={isAdding ? linkedUsers : users}
            renderCard={renderCard}
            searchFields={[
              ["name"],
              ["email"],
              ["corporateInformation", "companyInformation", "name"],
              ["role", "label"],
              ["type"],
            ]}
          />
        </section>
      </>
    </>
  );
}
