'use client';

import { zodResolver } from '@hookform/resolvers/zod';
import cookies from 'js-cookie';
import { notFound, useRouter } from 'next/navigation';
import { useContext, useState } from 'react';
import { useForm } from 'react-hook-form';
import { useSWRConfig } from 'swr';
import * as z from 'zod';

import { usePuzzle } from '@/lib/hooks/use-puzzles';
import { getURL } from '@/lib/utils';

import { Button } from '@/components/ui/Button';
import { Form, FormControl, FormField, FormItem, FormLabel } from '@/components/ui/Form';
import { Input } from '@/components/ui/Input';
import ToHTML from '@/components/ui/ToHTML';

import { UserContext } from '@/context/user';
import { type Puzzle } from '@/lib/puzzles';
import { Loader2 } from 'lucide-react';
import { Separator } from '@/components/ui/Separator';

type Granted = {
  tries: number | null;
  score?: number | null;
  message?: string | null;
  success?: boolean | null;
};

export default function Puzzle({ token, id }: { token: string; id: number }) {
  const { data: me } = useContext(UserContext);
  const { data: puzzle, isLoading } = usePuzzle({ token, id });
  const router = useRouter();

  if (!puzzle && isLoading) {
    return <></>;
  }

  if (!puzzle) {
    notFound();
  }

  // TODO : add a check to see if the user is in the group of the puzzle
  if (me?.groups.length === 0) {
    router.push('/dashboard/puzzles');
  }

  return (
    <div className="flex h-full w-full flex-col justify-between space-y-4">
      <h1 className="text-2xl font-bold sm:text-3xl md:text-4xl">
        {puzzle.name}{' '}
        <span className="text-xl text-highlight-secondary">({puzzle.scoreMax} points)</span>
      </h1>
      <Separator />
      <div className="flex h-screen w-full overflow-y-auto">
        <ToHTML className="font-code text-xs sm:text-base" data={puzzle.content} />
      </div>
      {!puzzle.score ? (
        <InputForm puzzle={puzzle} />
      ) : (
        <div className="flex items-center justify-between">
          <div className="items-center gap-x-2">
            <p>
              Tentative{puzzle.tries && puzzle.tries > 1 ? 's' : ''} :{' '}
              <span className="text-brand-accent">{puzzle.tries}</span>
            </p>
            <p>
              Score : <span className="text-brand-accent">{puzzle.score}</span>
            </p>
          </div>
          <Button type="button" onClick={() => router.push(getURL(`/dashboard/puzzles`))}>
            Retour aux puzzles
          </Button>
        </div>
      )}
    </div>
  );
}

const InputFormSchema = z.object({
  answer: z.string().nonempty().trim(),
  code_file: z.any().optional()
});

function InputForm({ puzzle }: { puzzle?: Puzzle }) {
  const form = useForm<z.infer<typeof InputFormSchema>>({
    resolver: zodResolver(InputFormSchema),
    defaultValues: {
      answer: '',
      code_file: undefined
    }
  });

  const { mutate } = useSWRConfig();

  const [isLoading, setIsLoading] = useState(false);
  const [granted, setGranted] = useState<Granted | null>(null);

  async function onSubmit(data: z.infer<typeof InputFormSchema>) {
    setIsLoading(true);

    const formData = new FormData();

    if (data.code_file) {
      formData.append('code_file', data.code_file[0]);
    }

    formData.append('answer', data.answer);

    const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/puzzleResponse/${puzzle!.id}`, {
      method: 'POST',
      body: formData,
      headers: {
        Authorization: `Bearer ${cookies.get('token')}}`
      }
    });

    if (res.ok || res.status === 403 || res.status === 406 || res.status === 423) {
      const data = res.ok || res.status === 406 ? ((await res.json()) as Granted) : null;
      if (data && data.score) {
        mutate(`puzzles/${puzzle?.id}`);
      } else if (data && data.tries) setGranted(data);
      else if (res.ok && data?.success)
        setGranted({ tries: null, score: null, message: 'Réponse correcte' });
      else if (res.status === 423)
        setGranted({ tries: null, score: null, message: 'Réponse incorrecte' });
      else if (res.status === 403) mutate(`puzzles/${puzzle?.id}`);
    }

    setIsLoading(false);

    form.reset();
  }

  return (
    <Form {...form}>
      <form
        onSubmit={form.handleSubmit(onSubmit)}
        className="flex w-full flex-col items-end justify-between gap-4 sm:flex-row"
        encType="multipart/form-data"
      >
        <div className="flex w-full flex-col gap-2 sm:flex-row sm:gap-4">
          <FormField
            control={form.control}
            name="answer"
            render={({ field }) => (
              <FormItem>
                <FormLabel htmlFor="answer">Réponse</FormLabel>
                <FormControl>
                  <Input placeholder="CAPTAIN, LOOK !" autoComplete="off" {...field} />
                </FormControl>
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="code_file"
            render={({ field }) => (
              <FormItem>
                <FormLabel htmlFor="code_file">Fichier</FormLabel>
                <FormControl>
                  <Input {...field} type="file" />
                </FormControl>
              </FormItem>
            )}
          />
        </div>
        {granted && (
          <div className="flex flex-col items-center justify-center gap-2">
            <p className="text-brand-accent">{granted.message}</p>
            {granted.tries && (
              <p className="text-brand-accent">
                Il vous reste {granted.tries} tentative{granted.tries > 1 ? 's' : ''}
              </p>
            )}
          </div>
        )}
        <Button disabled={isLoading} className="w-full sm:w-44" variant="brand">
          {isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
          Envoyer
        </Button>
      </form>
    </Form>
  );
}
