import Tip from "@/components/ApprovalWorkflows/Tip";
import Button from "@/components/Low/Button";
import Input from "@/components/Low/Input";
import Select from "@/components/Low/Select";
import useApprovalWorkflows from "@/hooks/useApprovalWorkflows";
import { Module, ModuleTypeLabels } from "@/interfaces";
import { ApprovalWorkflow, ApprovalWorkflowStatus, ApprovalWorkflowStatusLabel, StepTypeLabel } from "@/interfaces/approval.workflow";
import { EntityWithRoles } from "@/interfaces/entity";
import { User } from "@/interfaces/user";
import { sessionOptions } from "@/lib/session";
import { mapBy, redirect, serialize } from "@/utils";
import { requestUser } from "@/utils/api";
import { getApprovalWorkflows } from "@/utils/approval.workflows.be";
import { getEntitiesWithRoles } from "@/utils/entities.be";
import { shouldRedirectHome } from "@/utils/navigation.disabled";
import { doesEntityAllow, findAllowedEntities } from "@/utils/permissions";
import { isAdmin } from "@/utils/users";
import { getSpecificUsers } from "@/utils/users.be";
import { createColumnHelper, flexRender, getCoreRowModel, useReactTable, getPaginationRowModel } from "@tanstack/react-table";
import axios from "axios";
import clsx from "clsx";
import { withIronSessionSsr } from "iron-session/next";
import Head from "next/head";
import Link from "next/link";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import { BsTrash } from "react-icons/bs";
import { FaRegEdit } from "react-icons/fa";
import { IoIosAddCircleOutline } from "react-icons/io";
import { toast, ToastContainer } from "react-toastify";

const StatusClassNames: { [key in ApprovalWorkflowStatus]: string } = {
	approved:
		"bg-green-100 text-green-800 border border-green-300 before:content-[''] before:w-2 before:h-2 before:bg-green-500 before:rounded-full before:inline-block before:mr-2",
	pending:
		"bg-orange-100 text-orange-800 border border-orange-300 before:content-[''] before:w-2 before:h-2 before:bg-orange-500 before:rounded-full before:inline-block before:mr-2",
	rejected:
		"bg-red-100 text-red-800 border border-red-300 before:content-[''] before:w-2 before:h-2 before:bg-red-500 before:rounded-full before:inline-block before:mr-2",
};

type CustomStatus = ApprovalWorkflowStatus | undefined;
type CustomEntity = EntityWithRoles["id"] | undefined;

const STATUS_OPTIONS = [
	{
		label: "Approved",
		value: "approved",
		filter: (x: ApprovalWorkflow) => x.status === "approved",
	},
	{
		label: "Pending",
		value: "pending",
		filter: (x: ApprovalWorkflow) => x.status === "pending",
	},
	{
		label: "Rejected",
		value: "rejected",
		filter: (x: ApprovalWorkflow) => x.status === "rejected",
	},
];

const columnHelper = createColumnHelper<ApprovalWorkflow>();

export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
	const user = await requestUser(req, res);
	if (!user) return redirect("/login");

	if (shouldRedirectHome(user) || !["admin", "developer", "teacher", "corporate", "mastercorporate"].includes(user.type)) return redirect("/");

	const entityIDS = mapBy(user.entities, "id");
	const entities = await getEntitiesWithRoles(isAdmin(user) ? undefined : entityIDS);
	const allowedEntities = findAllowedEntities(user, entities, "view_workflows");

	const workflows = await getApprovalWorkflows("active-workflows", allowedEntities.map(entity => entity.id));

	const allAssigneeIds: string[] = [
		...new Set(
			workflows
				.map(workflow => workflow.steps
					.map(step => step.assignees)
					.flat()
				).flat()
		)
	];

	return {
		props: serialize({
			user,
			initialWorkflows: workflows,
			workflowsAssignees: await getSpecificUsers(allAssigneeIds),
			userEntitiesWithLabel: allowedEntities,
		}),
	};
}, sessionOptions);

interface Props {
	user: User;
	initialWorkflows: ApprovalWorkflow[];
	workflowsAssignees: User[];
	userEntitiesWithLabel: EntityWithRoles[];
}

export default function ApprovalWorkflows({ user, initialWorkflows, workflowsAssignees, userEntitiesWithLabel }: Props) {
	const entitiesString = userEntitiesWithLabel.map(entity => entity.id).join(",");
	const { workflows, reload } = useApprovalWorkflows(entitiesString);
	const currentWorkflows = workflows || initialWorkflows;

	const [filteredWorkflows, setFilteredWorkflows] = useState<ApprovalWorkflow[]>([]);

	const [statusFilter, setStatusFilter] = useState<CustomStatus>(undefined);
	const [entityFilter, setEntityFilter] = useState<CustomEntity>(undefined);
	const [nameFilter, setNameFilter] = useState<string>("");

	const router = useRouter();

	/* const allowedEntities = useAllowedEntities(user, userEntitiesWithLabel, "view_workflows");
	const allowedSomeEntities = useAllowedEntitiesSomePermissions(user, userEntitiesWithLabel, ["view_workflows", "create_workflow"]); */

	const ENTITY_OPTIONS = [
		...userEntitiesWithLabel
			.map((entity) => ({
				label: entity.label,
				value: entity.id,
				filter: (x: ApprovalWorkflow) => x.entityId === entity.id,
			}))
			.sort((a, b) => a.label.localeCompare(b.label)),
	];

	useEffect(() => {
		const filters: Array<(workflow: ApprovalWorkflow) => boolean> = [];

		if (statusFilter && statusFilter !== undefined) {
			const statusOption = STATUS_OPTIONS.find((x) => x.value === statusFilter);
			if (statusOption && statusOption.filter) {
				filters.push(statusOption.filter);
			}
		}

		if (entityFilter && entityFilter !== undefined) {
			const entityOption = ENTITY_OPTIONS.find((x) => x.value === entityFilter);
			if (entityOption && entityOption.filter) {
				filters.push(entityOption.filter);
			}
		}

		if (nameFilter.trim() !== "") {
			const nameFilterFunction = (workflow: ApprovalWorkflow) => workflow.name.toLowerCase().includes(nameFilter.toLowerCase());
			filters.push(nameFilterFunction);
		}

		// Apply all filters
		const filtered = currentWorkflows.filter((workflow) => filters.every((filterFn) => filterFn(workflow)));
		setFilteredWorkflows(filtered);
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [currentWorkflows, statusFilter, entityFilter, nameFilter]);

	const handleNameFilterChange = (name: ApprovalWorkflow["name"]) => {
		setNameFilter(name);
	};

	const deleteApprovalWorkflow = (id: string | undefined, name: string) => {
		if (id === undefined) return;
		if (!confirm(`Are you sure you want to delete this Approval Workflow?`)) return;

		axios
			.delete(`/api/approval-workflows/${id}`)
			.then(() => {
				toast.success(`Successfully deleted ${name} Approval Workflow.`);
				reload();
			})
			.catch((reason) => {
				if (reason.response.status === 403) {
					toast.error("You do not have permission to delete this Approval Workflow!");
				} else {
					toast.error("Something went wrong, please try again later.");
				}
				return;
			});
	};

	const columns = [
		columnHelper.accessor("name", {
			header: "EXAM NAME",
			cell: (info) => <span className="font-medium">{info.getValue()}</span>,
		}),
		columnHelper.accessor("modules", {
			header: "MODULES",
			cell: (info) => (
				<div className="flex flex-wrap gap-2">
					{info.getValue().map((module: Module, index: number) => (
						<span
							key={index}
							/* className="inline-block rounded-full px-3 py-1 text-sm font-medium bg-indigo-100 border border-indigo-300 text-indigo-900"> */
							className={clsx("inline-block rounded-full px-3 py-1 text-sm font-medium text-white",
								module === "speaking" ? "bg-ielts-speaking" :
									module === "reading" ? "bg-ielts-reading" :
										module === "writing" ? "bg-ielts-writing" :
											module === "listening" ? "bg-ielts-listening" :
												module === "level" ? "bg-ielts-level" :
													"bg-slate-700"
							)}>
							{ModuleTypeLabels[module]}
						</span>
					))}
				</div>
			),
		}),
		columnHelper.accessor("status", {
			header: "STATUS",
			cell: (info) => (
				<span
					className={clsx(
						"inline-block rounded-full px-3 py-1 text-sm font-medium text-left w-[110px]",
						StatusClassNames[info.getValue()],
					)}>
					{ApprovalWorkflowStatusLabel[info.getValue()]}
				</span>
			),
		}),
		columnHelper.accessor("entityId", {
			header: "ENTITY",
			cell: (info) => <span className="font-medium">{userEntitiesWithLabel.find((entity) => entity.id === info.getValue())?.label}</span>,
		}),
		columnHelper.accessor("steps", {
			id: "currentAssignees",
			header: "CURRENT ASSIGNEES",
			cell: (info) => {
				const steps = info.row.original.steps;
				const currentStep = steps.find((step) => !step.completed);
				const rejected = steps.find((step) => step.rejected);

				if (rejected) return "";

				const assignees = currentStep?.assignees.map((assigneeId) => {
					const assignee = workflowsAssignees.find((user) => user.id === assigneeId);
					return assignee?.name || "Unknown Assignee";
				});

				return (
					<div className="flex flex-wrap gap-2">
						{assignees?.map((assigneeName: string, index: number) => (
							<span
								key={index}
								className="inline-block rounded-full px-3 py-1 text-sm font-medium bg-gray-100 border border-gray-300 text-gray-900">
								{assigneeName}
							</span>
						))}
					</div>
				);
			},
		}),
		columnHelper.accessor("steps", {
			id: "currentStep",
			header: "CURRENT STEP",
			cell: (info) => {
				const steps = info.row.original.steps;
				const currentStep = steps.find((step) => !step.completed);
				const rejected = steps.find((step) => step.rejected);

				return (
					<span className="font-medium">
						{currentStep && !rejected ? `Step ${currentStep.stepNumber}: ${StepTypeLabel[currentStep.stepType]}` : "Completed"}
					</span>
				);
			},
		}),
		columnHelper.accessor("steps", {
			header: "ACTIONS",
			id: "actions",
			cell: ({ row }) => {
				const steps = row.original.steps;
				const currentStep = steps.find((step) => !step.completed);
				const rejected = steps.find((step) => step.rejected);

				return (
					<div className="flex gap-4">
						<button
							data-tip="Delete"
							className="cursor-pointer tooltip"
							disabled={!doesEntityAllow(user, userEntitiesWithLabel.find(entity => entity.id === row.original.entityId)!, "delete_workflow")}
							onClick={(e) => {
								e.stopPropagation();
								deleteApprovalWorkflow(row.original._id?.toString(), row.original.name);
							}}>
							<BsTrash className="hover:text-mti-purple-light transition ease-in-out duration-300" />
						</button>

						{currentStep && !rejected && (
							<button
								data-tip="Edit"
								className="cursor-pointer tooltip"
								disabled={!doesEntityAllow(user, userEntitiesWithLabel.find(entity => entity.id === row.original.entityId)!, "edit_workflow")}
								onClick={(e) => {
									e.stopPropagation();
									router.push(`/approval-workflows/${row.original._id?.toString()}/edit`);
								}}>
								<FaRegEdit className="hover:text-mti-purple-light transition ease-in-out duration-300" />
							</button>
						)}
					</div>
				);
			},
		}),
	];

	const [pagination, setPagination] = useState({
		pageIndex: 0,
		pageSize: 10,
	});

	const table = useReactTable({
		data: filteredWorkflows,
		columns: columns,
		state: {
			pagination,
		},
		onPaginationChange: setPagination,
		getCoreRowModel: getCoreRowModel(),
		getPaginationRowModel: getPaginationRowModel(),
	});

	return (
		<>
			<Head>
				<title>Approval Workflows Panel | 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>
			<ToastContainer />
			<h1 className="text-2xl font-semibold">Approval Workflows</h1>

			<div className="flex flex-row">
				<Link href={"/approval-workflows/create"}>
					<Button color="purple" variant="solid" className="min-w-fit text-lg font-medium flex items-center gap-2 text-left">
						<IoIosAddCircleOutline className="size-6" />
						Configure Workflows
					</Button>
				</Link>
			</div>

			<div className="flex w-full items-center gap-4">
				<div className="flex w-full flex-col gap-3">
					<label className="text-mti-gray-dim text-base font-normal">Name</label>
					<Input name="nameFilter" type="text" value={nameFilter} onChange={handleNameFilterChange} placeholder="Filter by name..." />
				</div>
				<div className="flex w-full flex-col gap-3">
					<label className="text-mti-gray-dim text-base font-normal">Status</label>
					<Select
						options={STATUS_OPTIONS}
						value={STATUS_OPTIONS.find((x) => x.value === statusFilter)}
						onChange={(value) => setStatusFilter((value?.value as ApprovalWorkflowStatus) ?? undefined)}
						isClearable
						placeholder="Filter by status..."
					/>
				</div>
				<div className="flex w-full flex-col gap-3">
					<label className="text-mti-gray-dim text-base font-normal">Entity</label>
					<Select
						options={ENTITY_OPTIONS}
						value={ENTITY_OPTIONS.find((x) => x.value === entityFilter)}
						onChange={(value) => setEntityFilter((value?.value as CustomEntity) ?? undefined)}
						isClearable
						placeholder="Filter by entity..."
					/>
				</div>
			</div>

			<Tip text="An exam submission will instantiate the approval workflow configured for the exam author. The exam will be valid only when all the steps of the workflow have been approved."></Tip>

			<div className="px-6 pb-4 bg-mti-purple-ultralight rounded-2xl border-2 border-mti-purple-light border-opacity-40">
				<table className="w-full table-auto border-separate border-spacing-y-2" style={{ tableLayout: "auto" }}>
					<thead>
						{table.getHeaderGroups().map((headerGroup) => (
							<tr key={headerGroup.id}>
								{headerGroup.headers.map((header) => (
									<th key={header.id} className="px-3 py-2 text-left text-mti-purple-ultradark">
										{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
									</th>
								))}
							</tr>
						))}
					</thead>
					<tbody>
						{table.getRowModel().rows.map((row) => (
							<tr
								key={row.id}
								onClick={() => (window.location.href = `/approval-workflows/${row.original._id?.toString()}`)}
								style={{ cursor: "pointer" }}
								className="bg-purple-50">
								{row.getVisibleCells().map((cell, cellIndex) => {
									const lastCellIndex = row.getVisibleCells().length - 1;

									let cellClasses = "pl-3 pr-4 py-2 border-y-2 border-mti-purple-light border-opacity-60";
									if (cellIndex === 0) {
										cellClasses += " border-l-2 rounded-l-2xl";
									}
									if (cellIndex === lastCellIndex) {
										cellClasses += " border-r-2 rounded-r-2xl";
									}

									return (
										<td key={cellIndex} className={cellClasses}>
											{flexRender(cell.column.columnDef.cell, cell.getContext())}
										</td>
									);
								})}
							</tr>
						))}
					</tbody>
				</table>
				<div className="mt-2 flex flex-row gap-2 w-full justify-end items-center">
					<button
						onClick={() => table.setPageIndex(0)}
						disabled={!table.getCanPreviousPage()}
						className="px-3 py-2 rounded-md text-sm font-semibold text-mti-purple-ultradark border border-mti-purple-light 
        bg-white hover:bg-mti-purple-light hover:text-white transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
					>
						{"<<"}
					</button>
					<button
						onClick={() => table.previousPage()}
						disabled={!table.getCanPreviousPage()}
						className="px-3 py-2 rounded-md text-sm font-semibold text-mti-purple-ultradark border border-mti-purple-light 
        bg-white hover:bg-mti-purple-light hover:text-white transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
					>
						{"<"}
					</button>
					<span className="px-4 text-sm font-medium">
						Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()}
					</span>
					<button
						onClick={() => table.nextPage()}
						disabled={!table.getCanNextPage()}
						className="px-3 py-2 rounded-md text-sm font-semibold text-mti-purple-ultradark border border-mti-purple-light 
        bg-white hover:bg-mti-purple-light hover:text-white transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
					>
						{">"}
					</button>
					<button
						onClick={() => table.setPageIndex(table.getPageCount() - 1)}
						disabled={!table.getCanNextPage()}
						className="px-3 py-2 rounded-md text-sm font-semibold text-mti-purple-ultradark border border-mti-purple-light 
        bg-white hover:bg-mti-purple-light hover:text-white transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
					>
						{">>"}
					</button>
				</div>
			</div>
		</>
	);
}
