'use client';

import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Text } from '@/components/ui/text';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from '@/components/ui/form';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import {
  fnBool,
  IColumnConfig,
  SavedTableSettings,
  TableProps,
  ApiError,
} from '@/types';
import axios from 'axios';
import { useToast } from '@/hooks/use-toast';
import { Loader2 } from 'lucide-react';
import { API_ENDPOINTS, PAGINATION_PAGES } from '@/constants';
import { useDispatch } from 'react-redux';
import { AppDispatch, store } from '@/store/store';
import {
  setTableRecordPerPage,
  setTableSettingsData,
} from '@/store/slices/tableSettingsSlice';
import { globalApiPost } from '@/services/global/globalApiCalls';

// ------------------
// Schema
// ------------------
const FormSchema = z.object({
  items: z.array(z.string()).min(1, 'You have to select at least one item.'),
  RecordsPage: z.string(),
  id: z.string().optional(),
  setting_type: z.string(),
});

// ------------------
// Helpers
// ------------------
function isSavedTableSettings(
  res: ApiError | SavedTableSettings,
): res is SavedTableSettings {
  return (
    typeof (res as SavedTableSettings).record_per_page !== 'undefined' &&
    Array.isArray((res as SavedTableSettings).setting_pack)
  );
}

interface TableSettingsFormProps {
  setIsOpen: fnBool;
}

// ------------------
// Component
// ------------------
const TableSettingsForm: React.FC<TableProps & TableSettingsFormProps> = ({
  bucket,
  tableData,
  handlePaginatedRecords,
  setIsOpen,
}) => {
  const { columns, recordsPerPage } = tableData;
  const dispatch = useDispatch<AppDispatch>();
  const { toast } = useToast();

  const [orderedItems, setOrderedItems] = useState<IColumnConfig[]>([]);
  const [dragIndex, setDragIndex] = useState<number | null>(null);
  const [saving, setSaving] = useState(false);
  const [resetting, setResetting] = useState(false);

  const myProfile = store.getState().session?.user;
  const userId: number = Number(myProfile?.id || 0);

  const form = useForm<z.infer<typeof FormSchema>>({
    resolver: zodResolver(FormSchema),
    defaultValues: {
      items: [],
      RecordsPage: String(recordsPerPage),
      setting_type: bucket.table_setting_type,
    },
  });

  const watchedItems = form.watch('items');

  const allSelected = useMemo(
    () => watchedItems.length === orderedItems.length,
    [watchedItems.length, orderedItems.length],
  );

  const handleSelectAll = useCallback(() => {
    const allKeys = orderedItems.map((i) => i.key);
    form.setValue('items', allSelected ? [] : allKeys);
  }, [allSelected, orderedItems, form]);

  const handleDragStart = useCallback((index: number) => {
    setDragIndex(index);
  }, []);

  const handleDrop = useCallback(
    (index: number) => {
      if (dragIndex === null || dragIndex === index) return;
      setOrderedItems((prev) => {
        const updated = [...prev];
        const [moved] = updated.splice(dragIndex, 1);
        updated.splice(index, 0, moved);
        return updated;
      });
      setDragIndex(null);
    },
    [dragIndex],
  );

  const handleDragOver = useCallback((e: React.DragEvent) => {
    e.preventDefault();
  }, []);

  // ------------------
  // Save handler
  // ------------------
  const handleSubmit = useCallback(
    async (args: z.infer<typeof FormSchema>) => {
      try {
        setSaving(true);

        const payload = {
          setting_type: args.setting_type,
          user_id: userId,
          affiliate_user_id: 0,
          record_per_page: Number(args.RecordsPage),
          setting_pack: orderedItems.map((item) => ({
            key: item.key,
            title: item.title,
            is_checked: args.items.includes(item.key) ? 'true' : 'false',
          })),
        };

        const response = await globalApiPost<SavedTableSettings>(
          API_ENDPOINTS.TABLE_SETTING.SAVE_TABLE_SETTINGS,
          payload,
        );

        if (isSavedTableSettings(response)) {
          const { setting_pack, record_per_page } = response;

          dispatch(setTableSettingsData(setting_pack));
          dispatch(setTableRecordPerPage(record_per_page));

          toast({
            variant: 'success',
            title: 'Settings saved successfully',
            duration: 2000,
          });

          // handlePaginatedRecords(store.getState().tableSettings.current_page, {
          //   per_page: payload.record_per_page,
          // });
          handlePaginatedRecords(1, {
            per_page: payload.record_per_page,
          });

          setIsOpen(false);
        }
      } catch (error) {
        const errorMessage = axios.isAxiosError(error)
          ? error.response?.data?.message || 'Network error'
          : error instanceof Error
            ? error.message
            : 'Unknown error occurred';

        toast({
          variant: 'destructive',
          title: errorMessage,
          duration: 2000,
        });
      } finally {
        setSaving(false);
      }
    },
    [orderedItems, toast, userId, dispatch, handlePaginatedRecords, setIsOpen],
  );

  // ------------------
  // Reset handler
  // ------------------
  const handleResetSettings = useCallback(async () => {
    try {
      if (!bucket.columns) {
        toast({
          variant: 'destructive',
          title: 'No columns provided for reset',
          duration: 2000,
        });
        return;
      }

      setResetting(true);

      const response = await globalApiPost<SavedTableSettings>(
        API_ENDPOINTS.TABLE_SETTING.RESET_TABLE_SETTINGS,
        {
          user_id: userId,
          setting_type: bucket.table_setting_type,
          columns: bucket.columns,
        },
      );

      if (response) {
        const { setting_pack, record_per_page } = response as any;

        dispatch(setTableSettingsData(setting_pack));
        dispatch(setTableRecordPerPage(record_per_page));

        toast({
          variant: 'success',
          title: 'Settings reset successfully',
          duration: 2000,
        });

        // handlePaginatedRecords(store.getState().tableSettings.current_page, {});
        handlePaginatedRecords(1, {});

        setIsOpen(false);
      }
    } catch (error) {
      const errorMessage = axios.isAxiosError(error)
        ? error.response?.data?.message || 'Network error'
        : error instanceof Error
          ? error.message
          : 'Unknown error occurred';

      toast({
        variant: 'destructive',
        title: errorMessage,
        duration: 2000,
      });
    } finally {
      setResetting(false);
    }
  }, [bucket, toast, userId, dispatch, handlePaginatedRecords, setIsOpen]);
  // cleaned deps

  const handlePageChange = useCallback(
    (value: string) => {
      form.setValue('RecordsPage', value);
    },
    [form],
  );

  // ------------------
  // Effects
  // ------------------
  useEffect(() => {
    const checkedItems = orderedItems.filter(
      (item) => item.is_checked === 'true' || item.is_checked === true,
    );
    form.setValue(
      'items',
      checkedItems.map((item) => item.key),
    );
  }, [orderedItems, form]);

  useEffect(() => {
    if (columns?.length) {
      setOrderedItems(columns);
    }
  }, [columns]);

  // ------------------
  // Render
  // ------------------
  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(handleSubmit)} className="space-y-8">
        <input type="hidden" {...form.register('setting_type')} />

        <Text className="main-scroll-widget">
          <FormField
            control={form.control}
            name="RecordsPage"
            render={({ field }) => (
              <FormItem className="w-1/4 p-4 records-page-number flex justify-center items-center">
                <FormLabel>Number of records per page?</FormLabel>
                <Select onValueChange={handlePageChange} value={field.value}>
                  <FormControl>
                    <SelectTrigger>
                      <SelectValue placeholder={field.value} />
                    </SelectTrigger>
                  </FormControl>
                  <SelectContent className="number-records-widget">
                    {PAGINATION_PAGES.map((page) => (
                      <SelectItem key={page} value={String(page)}>
                        {page}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
                <FormMessage />
              </FormItem>
            )}
          />

          <FormField
            control={form.control}
            name="items"
            render={() => (
              <>
                <Text className="flex justify-between mb-2 show-Columns-area">
                  <Text className="show-follow-text">
                    Show the Following Columns
                  </Text>
                  <Text className="select-all-check flex gap-2">
                    <Checkbox
                      id="select-all"
                      checked={allSelected}
                      onCheckedChange={handleSelectAll}
                    />
                    <FormLabel
                      htmlFor="select-all"
                      className="text-sm font-normal cursor-pointer"
                    >
                      Select All
                    </FormLabel>
                  </Text>
                </Text>
                <FormMessage className="mb-2 text-red-500 all-checkbox-area" />

                <FormItem className="flex flex-wrap space-y-0 all-columns-widget">
                  {orderedItems.map((col, index) => {
                    const checkboxId = `checkbox-${col.key.replace(/\s/g, '-')}`;
                    const isChecked = watchedItems.includes(col.key);

                    return (
                      <div
                        key={col.key}
                        draggable
                        onDragStart={() => handleDragStart(index)}
                        onDragOver={handleDragOver}
                        onDrop={() => handleDrop(index)}
                        className="flex flex-row items-start space-x-3 space-y-0 w-2/6 p-2 m-0 columns-grid"
                      >
                        <Text className="checkbox-widget flex justify-between p-0 cursor-pointer">
                          <FormControl>
                            <Checkbox
                              id={checkboxId}
                              checked={isChecked}
                              value={col.key}
                              onCheckedChange={(checked) => {
                                const current = form.getValues('items');
                                form.setValue(
                                  'items',
                                  checked
                                    ? [...current, col.key]
                                    : current.filter((k) => k !== col.key),
                                );
                              }}
                            />
                          </FormControl>
                          <FormLabel
                            htmlFor={checkboxId}
                            className="text-sm font-normal cursor-pointer flex-grow"
                          >
                            {`${index + 1}. ${col.title}`}
                          </FormLabel>
                        </Text>
                      </div>
                    );
                  })}
                </FormItem>
              </>
            )}
          />
        </Text>

        <Text className="modal-footer flex justify-end items-end footer-modal text-right gap-2 m-0 pr-4 p-2">
          <Button
            type="button"
            onClick={handleResetSettings}
            disabled={saving || resetting}
            className="m-0 filter-search-btn tracking-wider w-40 primary-button"
          >
            {resetting ? (
              <>
                <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                Resetting...
              </>
            ) : (
              'Reset Settings'
            )}
          </Button>
          <Button
            type="submit"
            disabled={saving || resetting}
            className="m-0 filter-search-btn tracking-wider w-40 primary-button"
          >
            {saving ? (
              <>
                <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                Saving...
              </>
            ) : (
              'Save Settings'
            )}
          </Button>
        </Text>
      </form>
    </Form>
  );
};

export default React.memo(TableSettingsForm);
