import Button from "@/components/Low/Button";
import Checkbox from "@/components/Low/Checkbox";
import {PERMISSIONS} from "@/constants/userPermissions";
import {CorporateUser, TeacherUser, Type, User} from "@/interfaces/user";
import {USER_TYPE_LABELS} from "@/resources/user";
import axios from "axios";
import clsx from "clsx";
import {capitalize, uniqBy} from "lodash";
import moment from "moment";
import {useEffect, useState} from "react";
import ReactDatePicker from "react-datepicker";
import {toast} from "react-toastify";
import ShortUniqueId from "short-unique-id";
import {checkAccess, getTypesOfUser} from "@/utils/permissions";
import {PermissionType} from "@/interfaces/permissions";
import usePermissions from "@/hooks/usePermissions";
import Input from "@/components/Low/Input";
import CountrySelect from "@/components/Low/CountrySelect";
import useGroups from "@/hooks/useGroups";
import useUsers from "@/hooks/useUsers";
import {getUserName} from "@/utils/users";
import Select from "@/components/Low/Select";

const USER_TYPE_PERMISSIONS: {
	[key in Type]: {perm: PermissionType | undefined; list: Type[]};
} = {
	student: {
		perm: "createCodeStudent",
		list: [],
	},
	teacher: {
		perm: "createCodeTeacher",
		list: [],
	},
	agent: {
		perm: "createCodeCountryManager",
		list: ["student", "teacher", "corporate", "mastercorporate"],
	},
	corporate: {
		perm: "createCodeCorporate",
		list: ["student", "teacher"],
	},
	mastercorporate: {
		perm: undefined,
		list: ["student", "teacher", "corporate"],
	},
	admin: {
		perm: "createCodeAdmin",
		list: ["student", "teacher", "agent", "corporate", "admin", "mastercorporate"],
	},
	developer: {
		perm: undefined,
		list: ["student", "teacher", "agent", "corporate", "admin", "developer", "mastercorporate"],
	},
};

interface Props {
	user: User;
	users: User[];
	permissions: PermissionType[];
	onFinish: () => void;
}

export default function UserCreator({user, users, permissions, onFinish}: Props) {
	const [name, setName] = useState<string>();
	const [email, setEmail] = useState<string>();
	const [phone, setPhone] = useState<string>();
	const [passportID, setPassportID] = useState<string>();
	const [studentID, setStudentID] = useState<string>();
	const [country, setCountry] = useState(user?.demographicInformation?.country);
	const [group, setGroup] = useState<string | null>();
	const [availableCorporates, setAvailableCorporates] = useState<User[]>([]);
	const [selectedCorporate, setSelectedCorporate] = useState<string | null>();
	const [password, setPassword] = useState<string>();
	const [confirmPassword, setConfirmPassword] = useState<string>();
	const [expiryDate, setExpiryDate] = useState<Date | null>(
		user?.subscriptionExpirationDate ? moment(user?.subscriptionExpirationDate).toDate() : null,
	);
	const [isExpiryDateEnabled, setIsExpiryDateEnabled] = useState(true);
	const [isLoading, setIsLoading] = useState(false);
	const [type, setType] = useState<Type>("student");
	const [position, setPosition] = useState<string>();

	const {groups} = useGroups({admin: ["developer", "admin"].includes(user?.type) ? undefined : user?.id, userType: user?.type});

	useEffect(() => {
		if (!isExpiryDateEnabled) setExpiryDate(null);
	}, [isExpiryDateEnabled]);

	useEffect(() => {
		setAvailableCorporates(
			uniqBy(
				users.filter((u) => u.type === "corporate" && groups.flatMap((g) => g.participants).includes(u.id)),
				"id",
			),
		);
	}, [users, groups]);

	const createUser = () => {
		if (!name || name.trim().length === 0) return toast.error("Please enter a valid name!");
		if (!email || email.trim().length === 0) return toast.error("Please enter a valid e-mail address!");
		if (users.map((x) => x.email).includes(email.trim())) return toast.error("That e-mail is already in use!");
		if (!password || password.trim().length < 6) return toast.error("Please enter a valid password!");
		if (password !== confirmPassword) return toast.error("The passwords do not match!");

		setIsLoading(true);

		const body = {
			name,
			email,
			password,
			groupID: group,
			corporate: selectedCorporate || user.id,
			type,
			studentID: type === "student" ? studentID : undefined,
			expiryDate,
			demographicInformation: {
				passport_id: type === "student" ? passportID : undefined,
				phone,
				country,
				position,
			},
		};

		axios
			.post("/api/make_user", body)
			.then(() => {
				toast.success("That user has been created!");
				onFinish();

				setName("");
				setEmail("");
				setPhone("");
				setPassportID("");
				setStudentID("");
				setCountry(user?.demographicInformation?.country);
				setGroup(null);
				setSelectedCorporate(null);
				setExpiryDate(user?.subscriptionExpirationDate ? moment(user?.subscriptionExpirationDate).toDate() : null);
				setIsExpiryDateEnabled(true);
				setType("student");
				setPosition(undefined);
			})
			.catch((error) => {
				const data = error?.response?.data;
				if (!!data?.message) return toast.error(data.message);
				toast.error("Something went wrong! Please try again later!");
			})
			.finally(() => setIsLoading(false));
	};

	return (
		<div className="flex flex-col gap-4 border p-4 border-mti-gray-platinum rounded-xl">
			<div className="grid grid-cols-2 gap-4">
				<Input required label="Name" value={name} onChange={setName} type="text" name="name" placeholder="Name" />
				<Input label="E-mail" required value={email} onChange={setEmail} type="email" name="email" placeholder="E-mail" />

				<Input type="password" name="password" label="Password" value={password} onChange={setPassword} placeholder="Password" required />
				<Input
					type="password"
					name="confirmPassword"
					label="Confirm Password"
					value={confirmPassword}
					onChange={setConfirmPassword}
					placeholder="ConfirmPassword"
					required
				/>

				<div className="flex flex-col gap-4">
					<label className="font-normal text-base text-mti-gray-dim">Country *</label>
					<CountrySelect value={country} onChange={setCountry} />
				</div>

				<Input type="tel" name="phone" label="Phone number" value={phone} onChange={setPhone} placeholder="Phone number" required />

				{type === "student" && (
					<>
						<Input
							type="text"
							name="passport_id"
							label="Passport/National ID"
							onChange={setPassportID}
							value={passportID}
							placeholder="National ID or Passport number"
							required
						/>
						<Input type="text" name="studentID" label="Student ID" onChange={setStudentID} value={studentID} placeholder="Student ID" />
					</>
				)}

				{["student", "teacher"].includes(type) && !["corporate", "teacher"].includes(user?.type) && (
					<div className={clsx("flex flex-col gap-4")}>
						<label className="font-normal text-base text-mti-gray-dim">Corporate</label>
						<Select
							options={availableCorporates.map((u) => ({value: u.id, label: getUserName(u)}))}
							isClearable
							onChange={(e) => setSelectedCorporate(e?.value || undefined)}
						/>
					</div>
				)}

				{["corporate", "mastercorporate"].includes(type) && (
					<Input type="text" name="department" label="Department" onChange={setPosition} value={position} placeholder="Department" />
				)}

				{!(type === "corporate" && user.type === "corporate") && (
					<div
						className={clsx(
							"flex flex-col gap-4",
							(!["student", "teacher"].includes(type) || ["corporate", "teacher"].includes(user?.type)) &&
								!["corporate", "mastercorporate"].includes(type) &&
								"col-span-2",
						)}>
						<label className="font-normal text-base text-mti-gray-dim">Group</label>
						<Select
							options={groups
								.filter((x) => (!selectedCorporate ? true : x.admin === selectedCorporate))
								.map((g) => ({value: g.id, label: g.name}))}
							onChange={(e) => setGroup(e?.value || undefined)}
						/>
					</div>
				)}

				<div
					className={clsx(
						"flex flex-col gap-4",
						!checkAccess(user, ["developer", "admin", "corporate", "mastercorporate"]) && "col-span-2",
					)}>
					<label className="font-normal text-base text-mti-gray-dim">Type</label>
					{user && (
						<select
							defaultValue="student"
							value={type}
							onChange={(e) => setType(e.target.value as Type)}
							className="p-6 w-full min-w-[350px] min-h-[70px] flex justify-center text-sm font-normal rounded-full border focus:outline-none cursor-pointer bg-white">
							{Object.keys(USER_TYPE_LABELS)
								.filter((x) => {
									const {list, perm} = USER_TYPE_PERMISSIONS[x as Type];
									return checkAccess(user, getTypesOfUser(list), permissions, perm);
								})
								.map((type) => (
									<option key={type} value={type}>
										{USER_TYPE_LABELS[type as keyof typeof USER_TYPE_LABELS]}
									</option>
								))}
						</select>
					)}
				</div>

				<div className="flex flex-col gap-4">
					{user && checkAccess(user, ["developer", "admin", "corporate", "mastercorporate"]) && (
						<>
							<div className="-md:flex-row -md:items-center flex justify-between gap-2 md:flex-col 2xl:flex-row 2xl:items-center">
								<label className="text-mti-gray-dim text-base font-normal">Expiry Date</label>
								<Checkbox
									isChecked={isExpiryDateEnabled}
									onChange={setIsExpiryDateEnabled}
									disabled={!!user?.subscriptionExpirationDate}>
									Enabled
								</Checkbox>
							</div>
							{isExpiryDateEnabled && (
								<ReactDatePicker
									className={clsx(
										"flex min-h-[70px] w-full cursor-pointer justify-center rounded-full border p-6 text-sm font-normal focus:outline-none",
										"hover:border-mti-purple tooltip",
										"transition duration-300 ease-in-out",
									)}
									filterDate={(date) =>
										moment(date).isAfter(new Date()) &&
										(user?.subscriptionExpirationDate ? moment(date).isBefore(user?.subscriptionExpirationDate) : true)
									}
									dateFormat="dd/MM/yyyy"
									selected={expiryDate}
									onChange={(date) => setExpiryDate(date)}
								/>
							)}
						</>
					)}
				</div>
			</div>

			<Button onClick={createUser} isLoading={isLoading} disabled={(isExpiryDateEnabled ? !expiryDate : false) || isLoading}>
				Create User
			</Button>
		</div>
	);
}
