"use client";

import {
  Dialog,
  DialogBackdrop,
  DialogPanel,
  DialogTitle,
  Transition,
  TransitionChild,
} from "@headlessui/react";
import { Checkbox } from "@/app/shadcn_components/ui/checkbox";

import { Fragment, useMemo, useState } from "react";
import { useMutation } from "@tanstack/react-query";
import { InputFile } from "@/app/portfolio/[slug]/components/InputFile";
import { ScenarioSelect } from "@/app/db/schema/recommendations";
import MeasuresCheckboxes from "./MeasuresCheckboxes";
import { useForm, FormProvider } from "react-hook-form";
import {
  SelectDropdown,
  SelectScenarioDropdown,
} from "@/app/portfolio/[slug]/components/RemoteAssessmentDropdowns";
import { Button } from "@/app/shadcn_components/ui/button";
import {
  FormField,
  FormItem,
  FormLabel,
  FormControl,
  FormMessage,
} from "@/app/shadcn_components/ui/form";
import { Input } from "@/app/shadcn_components/ui/input";
import { measuresList } from "@/app/db/schema/recommendations";
import { useRouter } from "next/navigation";
import { useSession } from "next-auth/react";
import { zodResolver } from "@hookform/resolvers/zod";
import {
  uploadCsvSchema,
  UploadCsvFormValues,
} from "@/app/portfolio/[slug]/components/FormSchema";
import * as XLSX from "xlsx";

const NEW_SENTINEL = "__new__";

const MAX_FILE_SIZE_MB = 20;

const allowedMimeTypes = [
  "text/csv",
  "application/vnd.ms-excel",
  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
];

const selecthousingTypeOptions = [
  { label: "Social", value: "Social", disabled: false },
  { label: "Private", value: "Private", disabled: false },
];

const selectGoalOptions = [
  { label: "Increasing EPC", value: "Increasing EPC", disabled: false },
  // {
  //   label: "Reduce energy consumption",
  //   value: "Reduce energy consumption",
  //   disabled: false,
  // },
];

const goalValueOptions = [
  { label: "C", value: "C", disabled: false },
  { label: "B", value: "B", disabled: false },
  { label: "A", value: "A", disabled: false },
];

function generateS3Key(
  userId: string,
  portfolioId: string,
  fileType: "csv" | "xlsx"
) {
  const timestamp = new Date().toISOString().replace(/[:.-]/g, "");
  return `${userId}/${portfolioId}/${timestamp}/asset_list.${fileType}`;
}

export async function validateClientFile(file: File): Promise<{
  isValid: boolean;
  error?: string;
  file_type?: "csv" | "xlsx";
  isStandardised?: boolean;
  sheetNames?: string[];
  sheetRowCounts?: Record<string, number>;
  fileFormat?: "domna_asset_list" | null;
}> {
  const sizeMB = file.size / (1024 * 1024);
  if (sizeMB > MAX_FILE_SIZE_MB) {
    return {
      isValid: false,
      error: `File is too large. Max size is ${MAX_FILE_SIZE_MB}MB.`,
    };
  }

  const filename = file.name.toLowerCase();
  const mimeType = file.type;

  let fileType: "csv" | "xlsx" | "unknown" = "unknown";

  if (
    filename.endsWith(".csv") ||
    mimeType === "text/csv" ||
    mimeType === "application/vnd.ms-excel"
  ) {
    fileType = "csv";
  } else if (
    filename.endsWith(".xlsx") ||
    filename.endsWith(".xls") ||
    mimeType ===
      "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  ) {
    fileType = "xlsx";
  }

  if (fileType === "unknown") {
    return {
      isValid: false,
      error: "Unsupported file type. Only CSV or Excel allowed.",
    };
  }

  let isStandardised = false;
  let sheetNames: string[] = [];
  let sheetRowCounts: Record<string, number> = {};

  if (fileType === "csv") {
    const text = await file.text();
    const lines = text.split("\n").map((line) => line.split(","));
    const headers = lines[0].map((h) => h.trim());
    isStandardised = headers.includes("domna_property_id");

    return {
      isValid: true,
      file_type: "csv",
      isStandardised,
      fileFormat: isStandardised ? "domna_asset_list" : null,
    };
  }

  if (fileType === "xlsx") {
    const arrayBuffer = await file.arrayBuffer();

    const workbook = XLSX.read(arrayBuffer, { type: "array" });
    sheetNames = workbook.SheetNames;

    for (const sheetName of sheetNames) {
      const worksheet = workbook.Sheets[sheetName];
      if (!worksheet) continue;

      const jsonData = XLSX.utils.sheet_to_json(worksheet, {
        header: 1,
      }) as any[][];

      if (sheetName === "Standardised Asset List") {
        const headers = jsonData[0] as string[];
        isStandardised = headers?.includes("domna_property_id");
      }

      // Count data rows, ignoring trailing blank rows and headers
      const rowCount = jsonData
        .slice(1) // skip header
        .filter((row) =>
          row.some((cell) => cell !== undefined && cell !== null && cell !== "")
        ).length;

      sheetRowCounts[sheetName] = rowCount;
    }

    if (!isStandardised) {
      // Explain why the file is not standardised

      return {
        isValid: false,
        error:
          "Excel file is not a valid domna asset list - either no 'Standardised Asset List' tab or no domna property ID reference.",
        file_type: "xlsx",
        sheetNames,
        sheetRowCounts,
      };
    }

    return {
      isValid: true,
      file_type: "xlsx",
      isStandardised,
      fileFormat: "domna_asset_list",
      sheetNames,
      sheetRowCounts,
    };
  }

  // fallback
  return {
    isValid: true,
    file_type: fileType,
    isStandardised: false,
  };
}

async function uploadCsvToS3({
  presignedUrl,
  file,
}: {
  presignedUrl: string;
  file: File;
}) {
  const response = await fetch(presignedUrl, {
    method: "PUT",
    body: file,
    headers: { "Content-Type": "text/csv" },
  });

  if (!response.ok) throw new Error("Upload failed");
  return { success: true };
}

async function generatePresignedUrl({
  userId,
  portfolioId,
  fileKey,
}: {
  userId: string;
  portfolioId: string;
  fileKey: string;
}) {
  const response = await fetch("/api/upload/csv", {
    method: "POST",
    body: JSON.stringify({ userId, portfolioId, fileKey }),
  });

  if (!response.ok) throw new Error("Failed to generate presigned URL");
  const data = await response.json();
  return { url: data.url, fileKey };
}
export function useUploadCsvPlan({
  file,
  portfolioId,
  goal,
  goalValue,
  housingType,
  scenarioName,
  scenarioId,
  selectedSheet,
  sheetCount,
  budget,
  ashpCop,
  measures,
  onSuccessRedirect,
  fileType,
  fileFormat,
  enforceFabricFirst,
}: {
  file: File;
  portfolioId: string;
  goal: string;
  goalValue: string;
  budget: number | null;
  ashpCop: number;
  housingType: string;
  scenarioName: string;
  scenarioId?: string | null;
  selectedSheet: string;
  sheetCount: number;
  measures: (typeof measuresList)[number][];
  onSuccessRedirect: (path: string) => void;
  fileType: "csv" | "xlsx";
  fileFormat: "domna_asset_list" | null;
  enforceFabricFirst: boolean;
}) {
  const session = useSession();
  const userId = String(session.data?.user.dbId);

  const fileKey = useMemo(
    () => generateS3Key(userId, portfolioId, fileType),
    [userId, portfolioId, fileType]
  );

  const { mutateAsync: uploadFileToS3, isLoading: isUploadLoading } =
    useMutation(uploadCsvToS3);

  const { mutateAsync: getPresignedUrl, isLoading: isGeneratingUrlLoading } =
    useMutation(generatePresignedUrl);

  const handleSubmit = async () => {
    try {
      const { url } = await getPresignedUrl({ userId, portfolioId, fileKey });

      await uploadFileToS3({ presignedUrl: url, file });

      const body = {
        scenario_id: scenarioName === NEW_SENTINEL ? null : scenarioId,
        portfolio_id: portfolioId,
        housing_type: housingType,
        goal: goal,
        goal_value: goalValue,
        trigger_file_path: fileKey,
        valuation_file_path: "", // Not used in this context
        already_installed_file_path: "",
        patches_file_path: "",
        non_invasive_recommendations_file_path: "",
        multi_plan: true,
        budget: budget === null ? null : Number(budget),
        scenario_name: scenarioName,
        inclusions: measures,
        event_type: "remote_assessment",
        sheet_name: selectedSheet,
        sheet_count: sheetCount,
        ashp_cop: Number(ashpCop),
        file_type: fileType, // Pass the file type for backend processing
        file_format: fileFormat,
        enforce_fabric_first: enforceFabricFirst,
      };

      const triggerRes = await fetch("/api/plan/trigger", {
        method: "POST",
        body: JSON.stringify(body),
      });

      if (!triggerRes.ok) throw new Error("Failed to trigger engine");

      onSuccessRedirect(`/portfolio/${portfolioId}/plan-loading`);
    } catch (err) {
      console.error("Upload or trigger failed", err);
      throw err;
    }
  };

  return {
    handleSubmit,
    isUploadLoading,
    isGeneratingUrlLoading,
  };
}

export default function UploadCsvModal({
  isOpen = false,
  setIsOpen,
  portfolioId,
  scenarios,
}: {
  isOpen?: boolean;
  setIsOpen: (open: boolean) => void;
  portfolioId: string;
  scenarios: ScenarioSelect[];
}) {
  const form = useForm<UploadCsvFormValues>({
    resolver: zodResolver(uploadCsvSchema),
    shouldUnregister: false,
    mode: "onChange",
    defaultValues: {
      scenario: "",
      housingType: "",
      goal: "",
      goalValue: "",
      budget: null,
      measures: measuresList,
    },
  });
  const { formState } = form;
  const { isValid, isSubmitting } = formState;

  const router = useRouter();

  const [sheetNames, setSheetNames] = useState<string[]>([]);
  const [selectedSheet, setSelectedSheet] = useState("");
  const [csvFile, setCsvFile] = useState<File | null>(null);
  const [selectedScenario, setSelectedScenario] = useState<string | null>(null);
  const [showMeasures, setShowMeasures] = useState(false);
  const [fileType, setFileType] = useState<"csv" | "xlsx">("csv");
  const [fileFormat, setFileFormat] = useState<"domna_asset_list" | null>(null);
  const [isValidating, setIsValidating] = useState(false);
  const [fileIsValid, setFileIsValid] = useState<boolean | null>(null);
  const [sheetCounts, setSheetCounts] = useState<Record<string, number>>({});
  const [errorMessage, setErrorMessage] = useState<string | null>(null);

  const scenarioOptions = useMemo(
    () =>
      scenarios.map((s) => ({
        label: s.name || "",
        value: String(s.id) || "",
        disabled: false,
      })),
    [scenarios]
  );

  const onSelectScenario = (opt: { value: string }) => {
    setSelectedScenario(opt.value);
    if (opt.value === NEW_SENTINEL) {
      form.reset({
        ...form.getValues(),
        scenario: "",
        housingType: "",
        goal: "",
        goalValue: "",
        ashpCop: 2.8, // Default COP value - eventually to come from db
      });
    } else {
      const picked = scenarios.find((s) => String(s.id) === opt.value);
      if (!picked) return;
      form.setValue("scenario", picked.name || "");
      form.setValue("housingType", picked.housingType);
      form.setValue("goal", picked.goal);
      form.setValue("goalValue", picked.goalValue || "");
      form.setValue("ashpCop", picked.ashpCop || 2.8); // Default COP value
      form.setValue("budget", picked.budget || null);
    }
  };

  const uploadCsvPlan = useUploadCsvPlan({
    file: csvFile!,
    goal: form.watch("goal"),
    goalValue: form.watch("goalValue"),
    housingType: form.watch("housingType"),
    budget: form.watch("budget") || null,
    ashpCop: form.watch("ashpCop"),
    scenarioName: form.watch("scenario"),
    scenarioId: selectedScenario === NEW_SENTINEL ? null : selectedScenario,
    measures: form.watch("measures"),
    fileType: fileType,
    fileFormat: fileFormat,
    portfolioId,
    selectedSheet,
    sheetCount: sheetCounts[selectedSheet] || 0,
    onSuccessRedirect: (path) => router.push(path),
    enforceFabricFirst: form.watch("enforce_fabric_first"),
  });

  const onSubmit = form.handleSubmit(async () => {
    if (!csvFile || !selectedSheet) return;
    await uploadCsvPlan.handleSubmit();
    form.reset();
  });

  return (
    <Transition appear show={isOpen} as={Fragment}>
      <Dialog
        as="div"
        className="fixed inset-0 z-10 overflow-y-auto"
        onClose={() => setIsOpen(false)}
      >
        <div className="min-h-screen px-4 text-center">
          <TransitionChild
            as={Fragment}
            enter="ease-out duration-300"
            enterFrom="opacity-0"
            enterTo="opacity-100"
            leave="ease-in duration-200"
            leaveFrom="opacity-100"
            leaveTo="opacity-0"
          >
            <DialogBackdrop className="fixed inset-0 bg-black bg-opacity-25" />
          </TransitionChild>
          <span
            className="inline-block h-screen align-middle"
            aria-hidden="true"
          >
            &#8203;
          </span>
          <TransitionChild
            as={Fragment}
            enter="ease-out duration-300"
            enterFrom="opacity-0 scale-95"
            enterTo="opacity-100 scale-100"
            leave="ease-in duration-200"
            leaveFrom="opacity-100 scale-100"
            leaveTo="opacity-0 scale-95"
          >
            <div className="inline-block w-full max-w-2xl p-6 my-8 overflow-visible text-left align-middle transition-all transform bg-white shadow-xl rounded-2xl">
              <DialogTitle className="text-lg font-medium">
                Upload Property Data
              </DialogTitle>
              <FormProvider {...form}>
                <form
                  onSubmit={onSubmit}
                  className="flex flex-col flex-grow gap-6 mt-6"
                >
                  {/* File Upload */}
                  <div className="flex flex-col gap-2">
                    <InputFile
                      onFileSelect={async (file) => {
                        setIsValidating(true);
                        setFileIsValid(null);

                        const result = await validateClientFile(file);
                        setIsValidating(false);

                        if (!result.isValid) {
                          setFileIsValid(false);
                          // Set validation message
                          setErrorMessage(
                            result.error || "File validation failed"
                          );
                          setCsvFile(null);
                          setSheetNames([]);
                          setSelectedSheet("");
                          return;
                        }

                        setFileIsValid(true);
                        setCsvFile(file);
                        setFileType(result.file_type!);
                        setFileFormat(result.fileFormat ?? null);
                        setSheetCounts(result.sheetRowCounts || {});

                        if (result.sheetNames) {
                          setSheetNames(result.sheetNames);
                          setSelectedSheet(result.sheetNames[0] || "");
                        } else {
                          setSheetNames([]);
                          setSelectedSheet("");
                        }
                      }}
                      isValidating={isValidating}
                      isValid={fileIsValid}
                      errorMessage={errorMessage}
                    />

                    <a
                      href="/example_properties.csv"
                      className="text-sm text-blue-600 underline w-fit"
                    >
                      View example CSV format
                    </a>
                  </div>

                  {/* Sheet selection */}
                  {sheetNames.length > 0 && (
                    <div className="flex flex-col gap-2">
                      <label className="text-sm font-medium text-gray-700">
                        Select the sheet/tab you want to use:
                      </label>
                      <SelectDropdown
                        options={sheetNames.map((name) => ({
                          label: name,
                          value: name,
                        }))}
                        selectedOption={selectedSheet}
                        onSelectOption={(opt) => setSelectedSheet(opt.value)}
                      />
                      <p className="text-xs text-gray-500">
                        Ensure this sheet uses the Standardised Asset List
                        format.
                      </p>
                    </div>
                  )}

                  {/* Scenario selection */}
                  <FormItem>
                    <FormLabel>Select scenario</FormLabel>
                    <FormControl>
                      <SelectScenarioDropdown
                        scenarios={scenarioOptions}
                        selectedValue={selectedScenario}
                        onSelect={onSelectScenario}
                      />
                    </FormControl>
                  </FormItem>

                  {/* Scenario definition inputs */}
                  {selectedScenario !== null && (
                    <>
                      <div className="grid grid-cols-2 gap-4">
                        {/* Scenario Name */}
                        <FormField
                          control={form.control}
                          name="scenario"
                          render={({ field }) => (
                            <FormItem>
                              <FormLabel className="text-gray-800">
                                Scenario Name
                              </FormLabel>
                              <FormControl>
                                <Input
                                  {...field}
                                  disabled={selectedScenario !== NEW_SENTINEL}
                                  placeholder="Scenario name"
                                  className="border-brandbrown focus-visible:ring-brandbrown focus-visible:border-brandbrown"
                                />
                              </FormControl>
                              <FormMessage className="text-brandbrown" />
                            </FormItem>
                          )}
                        />

                        {/* Housing Type */}
                        <FormField
                          control={form.control}
                          name="housingType"
                          render={({ field }) => (
                            <FormItem>
                              <FormLabel className="text-gray-800">
                                Housing Type
                              </FormLabel>
                              <FormControl>
                                {selectedScenario === NEW_SENTINEL ? (
                                  <SelectDropdown
                                    options={selecthousingTypeOptions}
                                    selectedOption={field.value}
                                    onSelectOption={(o) =>
                                      field.onChange(o.value)
                                    }
                                  />
                                ) : (
                                  <Input value={field.value} disabled />
                                )}
                              </FormControl>
                              <FormMessage className="text-brandbrown" />
                            </FormItem>
                          )}
                        />
                      </div>

                      <div className="grid grid-cols-2 gap-4">
                        {/* Goal */}
                        <FormField
                          control={form.control}
                          name="goal"
                          render={({ field }) => (
                            <FormItem>
                              <FormLabel className="text-gray-800">
                                Goal
                              </FormLabel>
                              <FormControl>
                                {selectedScenario === NEW_SENTINEL ? (
                                  <SelectDropdown
                                    options={selectGoalOptions}
                                    selectedOption={field.value}
                                    onSelectOption={(o) =>
                                      field.onChange(o.value)
                                    }
                                  />
                                ) : (
                                  <Input value={field.value} disabled />
                                )}
                              </FormControl>
                              <FormMessage className="text-brandbrown" />
                            </FormItem>
                          )}
                        />

                        {/* Goal Value */}
                        <FormField
                          control={form.control}
                          name="goalValue"
                          render={({ field }) => (
                            <FormItem>
                              <FormLabel className="text-gray-800">
                                Goal Value
                              </FormLabel>
                              <FormControl>
                                {selectedScenario === NEW_SENTINEL ? (
                                  <SelectDropdown
                                    options={goalValueOptions}
                                    selectedOption={field.value}
                                    onSelectOption={(opt) =>
                                      field.onChange(opt.value)
                                    }
                                  />
                                ) : (
                                  <Input value={field.value} disabled />
                                )}
                              </FormControl>
                              <FormMessage className="text-brandbrown" />
                            </FormItem>
                          )}
                        />
                      </div>

                      <div className="grid grid-cols-2 gap-4">
                        {/* Heat Pump COP */}
                        <FormField
                          control={form.control}
                          name="ashpCop"
                          render={({ field }) => (
                            <FormItem>
                              <FormLabel className="text-gray-800">
                                Heat Pump COP
                              </FormLabel>
                              <FormControl>
                                <Input
                                  type="number"
                                  step="0.1"
                                  placeholder="e.g. 2.8"
                                  {...field}
                                  value={
                                    field.value === undefined ? "" : field.value
                                  }
                                  disabled={selectedScenario !== NEW_SENTINEL}
                                />
                              </FormControl>
                              <FormMessage className="text-brandbrown" />
                            </FormItem>
                          )}
                        />

                        {/* Budget */}
                        <FormField
                          control={form.control}
                          name="budget"
                          render={({ field }) => (
                            <FormItem>
                              <FormLabel className="text-gray-800">
                                Budget (£)
                              </FormLabel>
                              <FormControl>
                                <Input
                                  type="number"
                                  step="1"
                                  placeholder="Optional"
                                  {...field}
                                  value={field.value ?? ""}
                                  disabled={selectedScenario !== NEW_SENTINEL}
                                />
                              </FormControl>
                              <FormMessage className="text-brandbrown" />
                            </FormItem>
                          )}
                        />
                      </div>
                    </>
                  )}

                  {/* Measures */}
                  <div className="border-t pt-4 mt-6">
                    <button
                      type="button"
                      onClick={() => setShowMeasures(!showMeasures)}
                      className="flex items-center justify-between w-full text-sm font-medium"
                    >
                      <span>Measures</span>
                      <span>{showMeasures ? "−" : "+"}</span>
                    </button>
                    <div className={showMeasures ? "" : "hidden"}>
                      <MeasuresCheckboxes form={form} />
                    </div>
                  </div>

                  {/*enforceFabricFirst checkbox */}
                  <FormField
                    control={form.control}
                    name="enforce_fabric_first"
                    render={({ field }) => (
                      <FormItem className="mt-6">
                        <div className="rounded-lg border border-gray-200 p-4">
                          <FormControl>
                            <label className="flex items-start gap-3 cursor-pointer">
                              <Checkbox
                                checked={field.value}
                                onCheckedChange={field.onChange}
                                // disabled={selectedScenario !== NEW_SENTINEL} // Always editable
                                className="mt-1"
                              />
                              <div className="flex flex-col">
                                <span className="text-sm font-medium text-gray-900">
                                  Enforce Fabric First
                                </span>
                                <span className="text-xs text-gray-500">
                                  Require insulation and fabric upgrades before
                                  heating measures are recommended.
                                </span>
                              </div>
                            </label>
                          </FormControl>
                          <FormMessage className="text-brandbrown mt-2" />
                        </div>
                      </FormItem>
                    )}
                  />

                  <div className="mt-auto pt-4 flex justify-end gap-4">
                    <Button
                      type="button"
                      variant="outline"
                      onClick={() => setIsOpen(false)}
                    >
                      Cancel
                    </Button>
                    <Button
                      type="submit"
                      disabled={
                        !csvFile || isValidating || !isValid || isSubmitting
                      }
                    >
                      {isSubmitting ? (
                        <div className="flex items-center gap-2">
                          <span className="loader h-4 w-4 border-2 border-t-transparent border-white rounded-full animate-spin" />
                          Submitting...
                        </div>
                      ) : (
                        "Submit"
                      )}
                    </Button>
                  </div>
                </form>
              </FormProvider>
            </div>
          </TransitionChild>
        </div>
      </Dialog>
    </Transition>
  );
}
