import { GlobeIcon, MoneyIcon } from "@/assets/icons";
import TagInput from "@/components/FormElements/InputGroup/tag-input";
import { TextAreaGroup } from "@/components/FormElements/InputGroup/text-area";
import MultiSelect from "@/components/FormElements/MultiSelect";
import { Select } from "@/components/FormElements/select";
import type { DynamicFormSection } from "@/components/forms/DynamicFormBuilder";
import { REGEX } from "@/constants/regex";
import { FormErrorMessages } from "@/constants/Texts";
import type { ICreateCompanyCredentials } from "@/lib/api";
import type { ILabelValue } from "@/types/shared";
import type { UseFormSetValue, UseFormWatch } from "react-hook-form";
import { v4 as uuidv4 } from "uuid";
import CompanyDocuments from "./documents/CompanyDocuments";
import CompanyLinks from "./links/CompanyLinks";

const companyInformationSectionId = uuidv4();
const businessInformationSectionId = uuidv4();
const settingsSectionId = uuidv4();
const addressSectionId = uuidv4();
const tagsSectionId = uuidv4();
const documentsSectionId = uuidv4();
const linksSectionId = uuidv4();

interface CompanyFormSectionsOptions {
  editMode?: boolean;
  id?: string;
  categoryItems: ILabelValue[];
  watch: UseFormWatch<ICreateCompanyCredentials>;
  setValue: UseFormSetValue<ICreateCompanyCredentials>;
  persistDocumentFileIds?: (ids: string[]) => Promise<void>;
}

const optionalNumber = (value: unknown) => {
  if (value === "" || value === null || value === undefined) return undefined;
  return Number(value);
};

const optionalNumberRange = ({
  min,
  max,
  integer = false,
}: {
  min: number;
  max: number;
  integer?: boolean;
}) => {
  return (value: unknown) => {
    const numberValue = optionalNumber(value);

    if (numberValue === undefined) return true;
    if (!Number.isFinite(numberValue)) return "Enter a valid number";
    if (integer && !Number.isInteger(numberValue)) {
      return "This field must be a whole number";
    }
    if (numberValue < min) return FormErrorMessages.min(min);
    if (numberValue > max) return FormErrorMessages.max(max);
    return true;
  };
};

const languageItems: ILabelValue[] = [
  { value: "en", label: "EN" },
  { value: "ar", label: "AR" },
  { value: "fr", label: "FR" },
  { value: "es", label: "ES" },
  { value: "de", label: "DE" },
  { value: "zh", label: "ZH" },
  { value: "jEna", label: "jEna" },
  { value: "ko", label: "KO" },
];

const currencyItems: ILabelValue[] = [
  { label: "USD", value: "USD" },
  { label: "EUR", value: "EUR" },
  { label: "GBP", value: "GBP" },
  { label: "JPY", value: "JPY" },
  { label: "CAD", value: "CAD" },
  { label: "AUD", value: "AUD" },
  { label: "CHF", value: "CHF" },
  { label: "CNY", value: "CNY" },
  { label: "INR", value: "INR" },
  { label: "BRL", value: "BRL" },
];

const allTimezones: Record<string, string> = {
  "Pacific/Midway": "Midway Island, Samoa",
  "Pacific/Honolulu": "Hawaii",
  "America/Juneau": "Alaska",
  "America/Boise": "Mountain Time",
  "America/Dawson": "Dawson, Yukon",
  "America/Chihuahua": "Chihuahua, La Paz, Mazatlan",
  "America/Phoenix": "Arizona",
  "America/Los_Angeles": "Pacific Time",
  "America/Chicago": "Central Time",
  "America/Regina": "Saskatchewan",
  "America/Mexico_City": "Guadalajara, Mexico City, Monterrey",
  "America/Belize": "Central America",
  "America/Detroit": "Eastern Time",
  "America/Bogota": "Bogota, Lima, Quito",
  "America/Caracas": "Caracas, La Paz",
  "America/Santiago": "Santiago",
  "America/St_Johns": "Newfoundland and Labrador",
  "America/Sao_Paulo": "Brasilia",
  "America/Tijuana": "Tijuana",
  "America/Montevideo": "Montevideo",
  "America/Argentina/Buenos_Aires": "Buenos Aires, Georgetown",
  "America/Godthab": "Greenland",
  "Atlantic/Azores": "Azores",
  "Atlantic/Cape_Verde": "Cape Verde Islands",
  GMT: "UTC",
  "Europe/London": "Edinburgh, London",
  "Europe/Dublin": "Dublin",
  "Europe/Lisbon": "Lisbon",
  "Africa/Casablanca": "Casablanca, Monrovia",
  "Atlantic/Canary": "Canary Islands",
  "Europe/Belgrade": "Belgrade, Bratislava, Budapest, Ljubljana, Prague",
  "Europe/Sarajevo": "Sarajevo, Skopje, Warsaw, Zagreb",
  "Europe/Brussels": "Brussels, Copenhagen, Madrid, Paris",
  "Europe/Amsterdam": "Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna",
  "Africa/Algiers": "West Central Africa",
  "Europe/Bucharest": "Bucharest",
  "Africa/Cairo": "Cairo",
  "Europe/Helsinki": "Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius",
  "Europe/Athens": "Athens",
  "Asia/Jerusalem": "Jerusalem",
  "Africa/Harare": "Harare, Pretoria",
  "Europe/Moscow": "Istanbul, Minsk, Moscow, St. Petersburg, Volgograd",
  "Asia/Kuwait": "Kuwait, Riyadh",
  "Africa/Nairobi": "Nairobi",
  "Asia/Baghdad": "Baghdad",
  "Asia/Tehran": "Tehran",
  "Asia/Dubai": "Abu Dhabi, Muscat",
  "Asia/Baku": "Baku, Tbilisi, Yerevan",
  "Asia/Kabul": "Kabul",
  "Asia/Yekaterinburg": "Ekaterinburg",
  "Asia/Karachi": "Islamabad, Karachi, Tashkent",
  "Asia/Kolkata": "Chennai, Kolkata, Mumbai, New Delhi",
  "Asia/Kathmandu": "Kathmandu",
  "Asia/Dhaka": "Astana, Dhaka",
  "Asia/Colombo": "Sri Jayawardenepura",
  "Asia/Almaty": "Almaty, Novosibirsk",
  "Asia/Rangoon": "Yangon Rangoon",
  "Asia/Bangkok": "Bangkok, Hanoi, Jakarta",
  "Asia/Krasnoyarsk": "Krasnoyarsk",
  "Asia/Shanghai": "Beijing, Chongqing, Hong Kong SAR, Urumqi",
  "Asia/Kuala_Lumpur": "Kuala Lumpur, Singapore",
  "Asia/Taipei": "Taipei",
  "Australia/Perth": "Perth",
  "Asia/Irkutsk": "Irkutsk, Ulaanbaatar",
  "Asia/Seoul": "Seoul",
  "Asia/Tokyo": "Osaka, Sapporo, Tokyo",
  "Asia/Yakutsk": "Yakutsk",
  "Australia/Darwin": "Darwin",
  "Australia/Adelaide": "Adelaide",
  "Australia/Sydney": "Canberra, Melbourne, Sydney",
  "Australia/Brisbane": "Brisbane",
  "Australia/Hobart": "Hobart",
  "Asia/Vladivostok": "Vladivostok",
  "Pacific/Guam": "Guam, Port Moresby",
  "Asia/Magadan": "Magadan, Solomon Islands, New Caledonia",
  "Asia/Kamchatka": "Kamchatka, Marshall Islands",
  "Pacific/Fiji": "Fiji Islands",
  "Pacific/Auckland": "Auckland, Wellington",
  "Pacific/Tongatapu": "Nuku'alofa",
};

const getTimezoneOffsetMinutes = (timezone: string, date = new Date()) => {
  try {
    const formatter = new Intl.DateTimeFormat("en", {
      timeZone: timezone,
      timeZoneName: "shortOffset",
    });
    const offset =
      formatter.formatToParts(date).find((part) => part.type === "timeZoneName")
        ?.value ?? "";
    const label = offset.replace(/^GMT/, "") || "+0";
    const match = label.match(/^([+-])(\d{1,2})(?::(\d{2}))?$/);

    if (!match) return 0;

    const sign = match[1] === "-" ? -1 : 1;
    const hours = Number(match[2]);
    const minutes = Number(match[3] ?? 0);

    return sign * (hours * 60 + minutes);
  } catch {
    return 0;
  }
};

const formatTimezoneOffset = (offsetMinutes: number) => {
  const sign = offsetMinutes < 0 ? "-" : "+";
  const absoluteMinutes = Math.abs(offsetMinutes);
  const hours = Math.trunc(absoluteMinutes / 60);
  const minutes = absoluteMinutes % 60;

  return `${sign}${hours}:${minutes.toString().padStart(2, "0")}`;
};

const hasTimezoneDst = (timezone: string) => {
  const januaryOffset = getTimezoneOffsetMinutes(
    timezone,
    new Date(new Date().getFullYear(), 0, 1),
  );
  const julyOffset = getTimezoneOffsetMinutes(
    timezone,
    new Date(new Date().getFullYear(), 6, 1),
  );

  return januaryOffset !== julyOffset;
};

const timezoneItems: ILabelValue[] = Object.entries(allTimezones)
  .map(([timezone, name]) => {
    const offsetMinutes = getTimezoneOffsetMinutes(timezone);

    return {
      timezone,
      name,
      hasDst: hasTimezoneDst(timezone),
      offsetMinutes,
    };
  })
  .sort((a, b) => a.offsetMinutes - b.offsetMinutes)
  .filter((item, index, items) => {
    return (
      items.findIndex(
        (timezone) =>
          timezone.offsetMinutes === item.offsetMinutes &&
          timezone.hasDst === item.hasDst,
      ) === index
    );
  })
  .map(({ timezone, name, offsetMinutes }) => ({
    label: `(GMT${formatTimezoneOffset(offsetMinutes)}) ${name}`,
    value: timezone,
  }));

export const createCompanyFormSections = ({
  editMode,
  id,
  categoryItems,
  watch,
  setValue,
  persistDocumentFileIds,
}: CompanyFormSectionsOptions): DynamicFormSection<ICreateCompanyCredentials>[] => [
  {
    id: companyInformationSectionId,
    title: "Company information",
    rootClassName: "lg:col-span-2",
    className: "gap-x-5 gap-y-5 sm:grid-cols-2 md:grid-cols-2",
    fields: [
      {
        kind: "input",
        name: "name",
        label: "Name",
        type: "text",
        placeholder: "Legal name as registered",
        required: true,
        className: "sm:col-span-2",
        rules: {
          required: { message: FormErrorMessages.required, value: true },
          minLength: { value: 2, message: FormErrorMessages.minLength(2) },
          maxLength: { value: 200, message: FormErrorMessages.maxLength(200) },
        },
      },
      {
        kind: "input",
        name: "email",
        label: "Email",
        type: "email",
        placeholder: "name@company.com",
        required: true,
        rules: {
          required: { message: FormErrorMessages.required, value: true },
          pattern: {
            value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
            message: FormErrorMessages.invalidEmail,
          },
        },
      },
      {
        kind: "input",
        name: "phone",
        label: "Phone",
        type: "tel",
        placeholder: "+971 50 123 4567",
        required: true,
        rules: {
          required: { message: FormErrorMessages.required, value: true },
          minLength: { value: 10, message: FormErrorMessages.minLength(10) },
          maxLength: { value: 20, message: FormErrorMessages.maxLength(20) },
          pattern: {
            value: REGEX.PHONE,
            message: FormErrorMessages.invalidPattern,
          },
        },
      },
      {
        kind: "custom",
        name: "type",
        render: ({ register, errors }) => (
          <Select<ICreateCompanyCredentials>
            {...register("type", {
              required: { message: FormErrorMessages.required, value: true },
            })}
            errors={errors}
            name="type"
            label="Company type"
            required
            items={[
              { value: "private", label: "Private" },
              { value: "public", label: "Public" },
              { value: "government", label: "Government" },
              { value: "ngo", label: "NGO" },
              { value: "startup", label: "Startup" },
            ]}
            defaultValue="Private"
            prefixIcon={<GlobeIcon />}
          />
        ),
      },
      {
        kind: "input",
        name: "industry",
        label: "Industry",
        type: "text",
        placeholder: "e.g. construction, software, logistics",
        rules: {
          minLength: { value: 2, message: FormErrorMessages.minLength(2) },
          maxLength: { value: 100, message: FormErrorMessages.maxLength(100) },
        },
      },
      {
        kind: "input",
        name: "registration_number",
        label: "Registration number",
        type: "text",
        placeholder: "Registry or license number",
        rules: {
          minLength: { value: 5, message: FormErrorMessages.minLength(5) },
          maxLength: { value: 50, message: FormErrorMessages.maxLength(50) },
        },
      },
      {
        kind: "input",
        name: "tax_id",
        label: "Tax id",
        type: "text",
        placeholder: "National tax identification number",
        rules: {
          minLength: { value: 5, message: FormErrorMessages.minLength(5) },
          maxLength: { value: 50, message: FormErrorMessages.maxLength(50) },
        },
      },
      {
        kind: "input",
        name: "website",
        label: "Website",
        type: "text",
        placeholder: "https://www.example.com",
        required: true,
        className: "sm:col-span-2",
        rules: {
          required: { message: FormErrorMessages.required, value: true },
          minLength: { value: 2, message: FormErrorMessages.minLength(2) },
          maxLength: { value: 100, message: FormErrorMessages.maxLength(100) },
          pattern: {
            value: REGEX.URL,
            message: FormErrorMessages.invalidPattern,
          },
        },
      },
      {
        kind: "custom",
        name: "description",
        className: "sm:col-span-2",
        render: ({ register, errors }) => (
          <TextAreaGroup<ICreateCompanyCredentials>
            label="Description"
            {...register("description", {
              minLength: {
                value: 10,
                message: FormErrorMessages.minLength(10),
              },
              maxLength: {
                value: 1000,
                message: FormErrorMessages.maxLength(1000),
              },
            })}
            errors={errors}
            name="description"
          />
        ),
      },
    ],
  },
  {
    id: businessInformationSectionId,
    title: "Business information",
    className: "gap-x-5 gap-y-5 sm:grid-cols-2 md:grid-cols-2",
    fields: [
      {
        kind: "input",
        name: "employee_count",
        label: "Employee count",
        type: "number",
        rules: {
          setValueAs: optionalNumber,
          validate: optionalNumberRange({ min: 1, max: 100000, integer: true }),
        },
      },
      {
        kind: "input",
        name: "annual_revenue",
        label: "Annual revenue",
        type: "number",
        rules: {
          setValueAs: optionalNumber,
          validate: optionalNumberRange({ min: 0, max: 999999999999 }),
        },
      },
      {
        kind: "input",
        name: "founded_year",
        label: "Founded year",
        type: "number",
        className: "sm:col-span-2",
        rules: {
          setValueAs: optionalNumber,
          validate: optionalNumberRange({
            min: 1800,
            max: 2100,
            integer: true,
          }),
        },
      },
    ],
  },
  {
    id: settingsSectionId,
    title: "Settings",
    className: "gap-x-5 gap-y-5 sm:grid-cols-2 md:grid-cols-2",
    fields: [
      {
        kind: "custom",
        name: "language",
        render: ({ register, errors }) => (
          <Select<ICreateCompanyCredentials>
            {...register("language")}
            errors={errors}
            name="language"
            label="Language"
            items={languageItems}
            defaultValue="en"
            prefixIcon={<GlobeIcon />}
          />
        ),
      },
      {
        kind: "custom",
        name: "currency",
        render: ({ register, errors }) => (
          <Select<ICreateCompanyCredentials>
            {...register("currency")}
            errors={errors}
            name="currency"
            label="Currency"
            items={currencyItems}
            defaultValue="USD"
            prefixIcon={<MoneyIcon />}
          />
        ),
      },
      {
        kind: "custom",
        name: "timezone",
        className: "sm:col-span-2",
        render: ({ register, errors }) => (
          <Select<ICreateCompanyCredentials>
            {...register("timezone")}
            errors={errors}
            name="timezone"
            label="Timezone"
            items={timezoneItems}
            value={watch("timezone") ?? ""}
            placeholder="Select timezone"
            searchable
            searchPlaceholder="Search timezone..."
            clearable
            onClear={() => setValue("timezone", "")}
          />
        ),
      },
    ],
  },
  {
    id: addressSectionId,
    title: "Address",
    className: "gap-x-5 gap-y-5 sm:grid-cols-2 md:grid-cols-2",
    fields: [
      {
        kind: "input",
        name: "address.street",
        label: "Street",
        type: "text",
        placeholder: "Building, street, suite or unit",
        className: "sm:col-span-2",
        rules: {
          minLength: { value: 5, message: FormErrorMessages.minLength(5) },
          maxLength: { value: 200, message: FormErrorMessages.maxLength(200) },
        },
      },
      {
        kind: "input",
        name: "address.city",
        label: "City",
        type: "text",
        placeholder: "City or town",
        rules: {
          minLength: { value: 2, message: FormErrorMessages.minLength(2) },
          maxLength: { value: 100, message: FormErrorMessages.maxLength(100) },
        },
      },
      {
        kind: "input",
        name: "address.state",
        label: "State",
        type: "text",
        placeholder: "State, province, or region",
        rules: {
          minLength: { value: 2, message: FormErrorMessages.minLength(2) },
          maxLength: { value: 100, message: FormErrorMessages.maxLength(100) },
        },
      },
      {
        kind: "input",
        name: "address.postal_code",
        label: "Postal code",
        type: "text",
        placeholder: "Postal or ZIP code",
        rules: {
          minLength: { value: 3, message: FormErrorMessages.minLength(3) },
          maxLength: { value: 20, message: FormErrorMessages.maxLength(20) },
        },
      },
      {
        kind: "input",
        name: "address.country",
        label: "Country",
        type: "text",
        placeholder: "Full country name",
        rules: {
          minLength: { value: 2, message: FormErrorMessages.minLength(2) },
          maxLength: { value: 100, message: FormErrorMessages.maxLength(100) },
        },
      },
    ],
  },
  {
    id: tagsSectionId,
    title: "Tags",
    className: "gap-x-5 gap-y-5 sm:grid-cols-2 md:grid-cols-2",
    fields: [
      {
        kind: "custom",
        name: "tags.keywords",
        render: ({ register }) => (
          <TagInput<ICreateCompanyCredentials>
            {...register("tags.keywords")}
            name="tags.keywords"
            label="Keywords"
            placeholder=""
            register={register}
            setValue={setValue}
            watch={watch}
          />
        ),
      },
      {
        kind: "custom",
        name: "tags.categories",
        render: ({ register }) => (
          <MultiSelect<ICreateCompanyCredentials>
            {...register("tags.categories")}
            value={watch("tags.categories")}
            name="tags.categories"
            label="Categories"
            items={categoryItems}
            placeholder=""
          />
        ),
      },
      {
        kind: "custom",
        name: "tags.cpv_codes",
        render: ({ register }) => (
          <TagInput<ICreateCompanyCredentials>
            {...register("tags.cpv_codes")}
            label="CPV codes"
            name="tags.cpv_codes"
            shouldAddWithSpace
            watch={watch}
            setValue={setValue}
            placeholder=""
          />
        ),
      },
      {
        kind: "custom",
        name: "tags.certifications",
        render: ({ register }) => (
          <TagInput<ICreateCompanyCredentials>
            {...register("tags.certifications")}
            label="Certifications"
            name="tags.certifications"
            watch={watch}
            setValue={setValue}
            placeholder=""
          />
        ),
      },
      {
        kind: "custom",
        name: "tags.specializations",
        className: "sm:col-span-2",
        render: ({ register, error }) => (
          <>
            <TagInput<ICreateCompanyCredentials>
              {...register("tags.specializations")}
              label="Specializations"
              name="tags.specializations"
              watch={watch}
              setValue={setValue}
              placeholder=""
            />
            {error ? (
              <p className="mt-1.5 text-sm font-medium text-error">{error}</p>
            ) : null}
          </>
        ),
      },
    ],
  },
  {
    id: documentsSectionId,
    title: "Documents",
    rootClassName: "lg:col-span-2",
    className: "md:grid-cols-1",
    fields: [
      {
        kind: "custom",
        name: "document_file_ids",
        render: () => (
          <CompanyDocuments
            companyId={editMode ? id : undefined}
            value={watch("document_file_ids") ?? []}
            onChange={(ids) =>
              setValue("document_file_ids", ids, {
                shouldDirty: true,
                shouldTouch: true,
                shouldValidate: true,
              })
            }
            onRemovePersist={persistDocumentFileIds}
          />
        ),
      },
    ],
  },
  {
    id: linksSectionId,
    title: "Links",
    rootClassName: "lg:col-span-2",
    className: "md:grid-cols-1",
    fields: [
      {
        kind: "custom",
        name: "links",
        render: ({ control, errors, register }) => (
          <CompanyLinks control={control} errors={errors} register={register} />
        ),
      },
    ],
  },
];
