import Layout from "@/components/High/Layout";
import TicketDisplay from "@/components/High/TicketDisplay";
import Select from "@/components/Low/Select";
import Modal from "@/components/Modal";
import useTickets from "@/hooks/useTickets";
import useUser from "@/hooks/useUser";
import useUsers from "@/hooks/useUsers";
import {Ticket, TicketStatus, TicketStatusLabel, TicketType, TicketTypeLabel, TicketWithCorporate} from "@/interfaces/ticket";
import {sessionOptions} from "@/lib/session";
import {shouldRedirectHome} from "@/utils/navigation.disabled";
import {createColumnHelper, flexRender, getCoreRowModel, useReactTable} from "@tanstack/react-table";
import clsx from "clsx";
import {withIronSessionSsr} from "iron-session/next";
import moment from "moment";
import Head from "next/head";
import {useEffect, useState} from "react";
import {BsArrowDown, BsArrowUp} from "react-icons/bs";
import {ToastContainer} from "react-toastify";

const columnHelper = createColumnHelper<TicketWithCorporate>();

export const getServerSideProps = withIronSessionSsr(({req, res}) => {
	const user = req.session.user;

	if (!user || !user.isVerified) {
		return {
			redirect: {
				destination: "/login",
				permanent: false,
			},
		};
	}

	if (shouldRedirectHome(user) || !["admin", "developer", "agent"].includes(user.type)) {
		return {
			redirect: {
				destination: "/",
				permanent: false,
			},
		};
	}

	return {
		props: {user: req.session.user},
	};
}, sessionOptions);

const StatusClassNames: {[key in TicketStatus]: string} = {
	submitted: "bg-mti-gray-dim",
	"in-progress": "bg-mti-blue-dark",
	completed: "bg-mti-green-dark",
};

const TypesClassNames: {[key in TicketType]: string} = {
	feedback: "bg-mti-green-light",
	bug: "bg-mti-red-dark",
	help: "bg-mti-blue-light",
};

const escapedURL = process.env.NEXT_PUBLIC_WEBSITE_URL || "".replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const fromHomepage = [new RegExp(`^${escapedURL}`), /\/contact$/];

type Source = "webpage" | "platform" | "";

const SOURCE_OPTIONS = [
	{value: "", label: "All"},
	{value: "webpage", label: "Webpage"},
	{value: "platform", label: "Platform"},
];

type CustomStatus = TicketStatus | "all" | "pending";

const STATUS_OPTIONS = [{
	label: 'Pending',
	value: 'pending',
	filter: (x: Ticket) => x.status !== 'completed',
}, {
	label: 'All',
	value: 'all',
	filter: (x: Ticket) => true,
}, {
	label: 'Completed',
	value: 'completed',
	filter: (x: Ticket) => x.status === 'completed',
}, {
	label: 'In Progress',
	value: 'in-progress',
	filter: (x: Ticket) => x.status === 'in-progress',
}, {
	label: 'Submitted',
	value: 'submitted',
	filter: (x: Ticket) => x.status === 'submitted',
}]

export default function Tickets() {
	const [filteredTickets, setFilteredTickets] = useState<Ticket[]>([]);
	const [selectedTicket, setSelectedTicket] = useState<Ticket>();
	const [assigneeFilter, setAssigneeFilter] = useState<string>();
	const [sourceFilter, setSourceFilter] = useState<Source>("");
	// const [statusFilter, setStatusFilter] = useState<CustomStatus>('pending');
	const [dateSorting, setDateSorting] = useState<"asc" | "desc">("desc");

	const [typeFilter, setTypeFilter] = useState<TicketType>();
	const [statusFilter, setStatusFilter] = useState<CustomStatus>('pending');

	const {user} = useUser({redirectTo: "/login"});
	const {users} = useUsers();
	const {tickets, reload} = useTickets();

	const sortByDate = (a: Ticket, b: Ticket) => {
		return moment((dateSorting === "desc" ? b : a).date).diff(moment((dateSorting === "desc" ? a : b).date));
	};

	useEffect(() => {
		const filters = [];
		if (user?.type === "agent") filters.push((x: Ticket) => x.assignedTo === user.id);
		if (typeFilter) filters.push((x: Ticket) => x.type === typeFilter);
		if (statusFilter) {
			const filter = STATUS_OPTIONS.find(x => x.value === statusFilter)?.filter;
			if (filter) filters.push(filter);
		}
		if (assigneeFilter) filters.push((x: Ticket) => x.assignedTo === assigneeFilter);
		if (sourceFilter) {
			if (sourceFilter === "webpage") filters.push((x: Ticket) => fromHomepage.some((r) => r.test(x.reportedFrom)));
			if (sourceFilter === "platform") filters.push((x: Ticket) => !fromHomepage.some((r) => r.test(x.reportedFrom)));
		}
		setFilteredTickets([...filters.reduce((d, f) => d.filter(f), tickets)].sort(sortByDate));
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [tickets, typeFilter, statusFilter, assigneeFilter, dateSorting, user, sourceFilter]);

	const columns = [
		columnHelper.accessor("id", {
			header: "ID",
			cell: (info) => info.getValue(),
		}),
		columnHelper.accessor("type", {
			header: "Type",
			cell: (info) => (
				<span className={clsx("rounded-lg p-1 px-2 text-white", TypesClassNames[info.getValue()])}>{TicketTypeLabel[info.getValue()]}</span>
			),
		}),
		columnHelper.accessor("reporter", {
			header: "Reporter",
			cell: (info) => info.getValue().email,
		}),
		columnHelper.accessor("reportedFrom", {
			header: "Reported From",
			cell: (info) => info.getValue(),
		}),
		columnHelper.accessor("date", {
			id: "date",
			header: (
				<button className="flex items-center gap-2" onClick={() => setDateSorting((prev) => (prev === "asc" ? "desc" : "asc"))}>
					<span>Date</span>
					{dateSorting === "desc" && <BsArrowDown />}
					{dateSorting === "asc" && <BsArrowUp />}
				</button>
			) as any,
			cell: (info) => <span className="whitespace-nowrap">{moment(info.getValue()).format("DD/MM/YYYY - HH:mm")}</span>,
		}),
		columnHelper.accessor("subject", {
			header: "Subject",
			cell: (info) => info.getValue().substring(0, 12) + (info.getValue().length > 12 ? "..." : ""),
		}),
		columnHelper.accessor("status", {
			header: "Status",
			cell: (info) => (
				<span className={clsx("rounded-lg p-1 px-2 text-white", StatusClassNames[info.getValue()])}>
					{TicketStatusLabel[info.getValue()]}
				</span>
			),
		}),
		columnHelper.accessor("assignedTo", {
			header: "Assignee",
			cell: (info) => users.find((x) => x.id === info.getValue())?.name || "",
		}),
		columnHelper.accessor("corporate", {
			header: "Corporate",
			cell: (info) => info.getValue(),
		}),
	];

	const getAssigneeValue = () => {
		if (user && user.type === "agent") return {value: user.id, label: `${user.name} - ${user.email}`};

		if (assigneeFilter) {
			const assigneeUser = users.find((x) => x.id === assigneeFilter);
			return assigneeUser
				? {
						value: assigneeFilter,
						label: `${assigneeUser.name} - ${assigneeUser.email}`,
				  }
				: null;
		}

		return null;
	};

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

	return (
		<>
			<Modal
				isOpen={!!selectedTicket}
				title={selectedTicket ? selectedTicket.id : undefined}
				onClose={() => {
					reload();
					setSelectedTicket(undefined);
				}}>
				{selectedTicket && (
					<TicketDisplay
						user={user!}
						ticket={selectedTicket}
						onClose={() => {
							reload();
							setSelectedTicket(undefined);
						}}
					/>
				)}
			</Modal>

			<Head>
				<title>Tickets 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 />
			{user && (
				<Layout user={user} className="gap-6">
					<h1 className="text-2xl font-semibold">Tickets</h1>

					<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">Status</label>
							<Select
								options={STATUS_OPTIONS}
								value={
									STATUS_OPTIONS.find((x) => x.value === statusFilter)
								}
								onChange={(value) => setStatusFilter((value?.value as TicketStatus) ?? undefined)}
								isClearable
								placeholder="Status..."
							/>
						</div>
						<div className="flex w-full flex-col gap-3">
							<label className="text-mti-gray-dim text-base font-normal">Type</label>
							<Select
								options={Object.keys(TicketTypeLabel).map((x) => ({
									value: x,
									label: TicketTypeLabel[x as keyof typeof TicketTypeLabel],
								}))}
								value={typeFilter ? {value: typeFilter, label: TicketTypeLabel[typeFilter]} : undefined}
								onChange={(value) => setTypeFilter((value?.value as TicketType) ?? undefined)}
								isClearable
								placeholder="Type..."
							/>
						</div>
						<div className="flex w-full flex-col gap-3">
							<label className="text-mti-gray-dim text-base font-normal">Assignee</label>
							<Select
								options={[
									{value: "me", label: "Assigned to me"},
									...users
										.filter((x) => ["admin", "developer", "agent"].includes(x.type))
										.map((u) => ({
											value: u.id,
											label: `${u.name} - ${u.email}`,
										})),
								]}
								disabled={user.type === "agent"}
								value={getAssigneeValue()}
								onChange={(value) =>
									value ? setAssigneeFilter(value.value === "me" ? user.id : value.value) : setAssigneeFilter(undefined)
								}
								placeholder="Assignee..."
								isClearable
							/>
						</div>
						<div className="flex w-full flex-col gap-3">
							<label className="text-mti-gray-dim text-base font-normal">Source</label>
							<Select
								options={SOURCE_OPTIONS}
								disabled={user.type === "agent"}
								value={SOURCE_OPTIONS.find((x) => x.value === sourceFilter)}
								onChange={(value) => setSourceFilter(value?.value as Source)}
							/>
						</div>
					</div>

					<table className="bg-mti-purple-ultralight/40 w-full rounded-xl">
						<thead>
							{table.getHeaderGroups().map((headerGroup) => (
								<tr key={headerGroup.id}>
									{headerGroup.headers.map((header) => (
										<th className="px-4 py-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={clsx(
										"even:bg-mti-purple-ultralight/40 hover:bg-mti-purple-ultralight cursor-pointer rounded-lg py-2 odd:bg-white",
										"transition duration-300 ease-in-out",
									)}
									onClick={() => setSelectedTicket(row.original)}
									key={row.id}>
									{row.getVisibleCells().map((cell) => (
										<td className="w-fit items-center px-4 py-2" key={cell.id}>
											{flexRender(cell.column.columnDef.cell, cell.getContext())}
										</td>
									))}
								</tr>
							))}
						</tbody>
					</table>
				</Layout>
			)}
		</>
	);
}
