"use client";

import { zodResolver } from "@hookform/resolvers/zod";
import Image from "next/image";
import type React from "react";
import { useRef, useState } from "react";
import { Controller, useForm } from "react-hook-form";
import z from "zod";
import type { PhotoData } from "@/server/api/routers/photos/list";
import { api } from "@/trpc/react";
import DirSvg from "./dir-svg";
import ImageSvg from "./file-svg";
import Tiptap from "./photo-editor";
import type { Editor } from "@tiptap/react";

// - TODO - Pull this from trpc
const FormSchema = z.object({
	title: z
		.string()
		.min(3, "Title should be over 3 characters")
		.max(128, "Title cannot be over 128 characters"),
	description: z.object({
		type: z.string(),
		content: z.array(z.unknown()),
	}),
});

type IFormInput = z.infer<typeof FormSchema>;

interface DirectoryTree {
	[key: string]: DirectoryTree;
}

function buildDirectoryTree(filePaths: string[]): DirectoryTree {
	const root: DirectoryTree = {};

	filePaths.forEach((path) => {
		const parts = path.split("/").filter((p) => p.length > 0);
		let current = root;

		// Traverse or create nodes for each part of the path
		for (let i = 0; i < parts.length; i++) {
			const part = parts[i];
			if (part) {
				if (!current[part]) {
					current[part] = {};
				}
				current = current[part];
			}
		}
	});

	return root;
}

type Item = {
	type: "directory" | "file";
	name: string;
	fullPath: string;
	children?: Item[];
};

function renderTree(node: DirectoryTree, pathSoFar = ""): Item[] {
	const entries = Object.entries(node);
	const items: Item[] = [];

	for (const [name, children] of entries) {
		const fullPath = pathSoFar ? `${pathSoFar}/${name}` : name;
		const isLeaf = Object.keys(children).length === 0;

		if (isLeaf) {
			// It's a file
			items.push({ type: "file", name, fullPath });
		} else {
			// It's a directory
			items.push({
				type: "directory",
				name,
				fullPath,
				children: renderTree(children, fullPath),
			});
		}
	}

	return items;
}

function RenderLeaf(
	leaf: Item[],
	selectImageTab: (path: string) => void,
	selectedImage: PhotoData | undefined,
) {
	return leaf.map((leaf) => {
		const selectedLeaf =
			`https://fly.storage.tigris.dev/joemonk-photos/${leaf.fullPath}` ===
			selectedImage?.src;
		if (leaf.children?.length) {
			return (
				<li key={leaf.fullPath}>
					<details open>
						<summary>
							<DirSvg />
							{leaf.name}
						</summary>
						<ul>{RenderLeaf(leaf.children, selectImageTab, selectedImage)}</ul>
					</details>
				</li>
			);
		}
		return (
			<li key={leaf.fullPath}>
				<button
					type="button"
					className={selectedLeaf ? "active" : ""}
					onClick={() => selectImageTab(leaf.fullPath)}
				>
					<ImageSvg />
					{leaf.name}
				</button>
			</li>
		);
	});
}

export function PhotoTab(): React.JSX.Element {
	const [selectedImage, setSelectedImage] = useState<PhotoData>();
	const editorRef = useRef<Editor>(null);
	const titleRef = useRef<HTMLInputElement>(null);
	const listQuery = api.photos.list.useInfiniteQuery(
		{},
		{
			getNextPageParam: (lastPage) => lastPage.next,
			refetchOnWindowFocus: false,
			refetchOnMount: false,
			refetchOnReconnect: false,
		},
	);
	const modifyMutate = api.photos.modify.useMutation();

	const {
		register,
		handleSubmit,
		setValue,
		control,
		formState: { errors },
	} = useForm<IFormInput>({
		resolver: zodResolver(FormSchema),
		mode: "onSubmit",
	});

	if (listQuery.isLoading) {
		return <p>Loading</p>;
	}
	if (listQuery.error) {
		return <p>{listQuery.error.message}</p>;
	}
	const images = listQuery.data?.pages.flatMap((data) => data.data);
	if (!images || images?.length === 0) {
		return <p>No Images</p>;
	}
	if (listQuery.hasNextPage) {
		listQuery.fetchNextPage();
	}

	const selectImage = (path: string) => {
		const img = images.find(
			(img) =>
				img.src === `https://fly.storage.tigris.dev/joemonk-photos/${path}`,
		);
		setSelectedImage(img);
		modifyMutate.reset();
		editorRef.current?.commands.setContent(img?.description ?? null);
		setValue("title", img?.title ?? "", { shouldTouch: true });
	};

	const tree = buildDirectoryTree(
		images.map((img) =>
			img.src.substring(
				"https://fly.storage.tigris.dev/joemonk-photos/".length,
			),
		),
	);
	const renderedTree = renderTree(tree);

	return (
		<div className="flex w-full gap-4 md:gap-2 flex-col md:flex-row">
			<ul className="menu menu-xs bg-base-200 box w-full md:w-1/4">
				{listQuery.hasNextPage || listQuery.isLoading ? (
					<progress className="progress w-full"></progress>
				) : null}
				{RenderLeaf(renderedTree, selectImage, selectedImage)}
			</ul>
			<div className="md:w-3/4 box border border-base-300 p-2 w-full">
				{selectedImage?.src ? (
					<form
						onSubmit={handleSubmit((data) =>
							modifyMutate.mutate({
								title: data.title,
								description: data.description,
								src: selectedImage.src,
							}),
						)}
					>
						<label
							className={`floating-label input text-lg mb-2 w-full ${errors.title ? "input-error" : null}`}
						>
							<span>{`Title ${errors.title ? ` - ${errors.title.message}` : ""}`}</span>
							<input
								{...register("title", { value: selectedImage?.title })}
								ref={titleRef}
								type="text"
								placeholder="Title"
							/>
						</label>
						<Image
							src={selectedImage.src}
							title={selectedImage?.title}
							alt={selectedImage?.title ?? "Image to modify data for"}
							width={selectedImage.width}
							height={selectedImage.height}
							blurDataURL={selectedImage.blur}
							placeholder="blur"
						/>
						<div className="mt-2 grid grid-cols-3">
							{[
								{
									title: "F-Stop",
									value: selectedImage.exif.fNumber?.toString(),
								},
								{
									title: "ISO",
									value: selectedImage.exif.isoSpeedRatings?.toString(),
								},
								{
									title: "Exposure",
									value: selectedImage.exif.exposureBiasValue?.toString(),
								},
							].map((setting) => {
								return (
									<div key={setting.title} className="w-full border">
										<span className="px-2 w-20 inline-block">
											{setting.title}
										</span>
										<span className="px-2">{setting.value}</span>
									</div>
								);
							})}
						</div>
						<div className="mt-2 grid grid-cols-3">
							{[
								{
									title: "Taken",
									value: selectedImage.exif.takenAt?.toLocaleDateString(),
								},
								{
									title: "Lens",
									value: selectedImage.exif.LensModel,
								},
								{
									title: "Camera",
									value: selectedImage.camera,
								},
							].map((setting) => {
								return (
									<div key={setting.title} className="w-full border">
										<span className="px-2 w-20 inline-block">
											{setting.title}
										</span>
										<span className="px-2">{setting.value}</span>
									</div>
								);
							})}
						</div>
						<div className="mt-2 grid grid-cols-2">
							{[
								{
									title: "Height",
									value: selectedImage.height.toString(),
								},
								{
									title: "Width",
									value: selectedImage.width.toString(),
								},
							].map((setting) => {
								return (
									<div key={setting.title} className="w-full border">
										<span className="px-2 w-20 inline-block">
											{setting.title}
										</span>
										<span className="px-2">{setting.value}</span>
									</div>
								);
							})}
						</div>
						<div className="mt-2 px-2 pb-2 border">
							<span>Description</span>

							<Controller
								control={control}
								name="description"
								render={({ field: { onChange } }) => (
									<Tiptap
										onChange={onChange}
										initContent={selectedImage.description}
										editorRef={editorRef}
									/>
								)}
							/>
						</div>
						<div className="flex flex-row items-center">
							<button
								className="btn btn-primary flex self-center m-4"
								type="submit"
							>
								Save
							</button>
							{modifyMutate.isSuccess ? (
								<p className="badge badge-success">Updated</p>
							) : modifyMutate.isError ? (
								<p className="badge badge-error">
									Error: {modifyMutate.error.message}
								</p>
							) : modifyMutate.isPending ? (
								<p className="badge badge-info">Updating</p>
							) : null}
						</div>
					</form>
				) : null}
			</div>
		</div>
	);
}
