import type { CoreMemberAccountType } from "@/lib/features/members/types";
import countries from "@/utils/multiselectCountry.json";
import { EmailRegex } from "@/utils/regex";
import {
  Button,
  Checkbox,
  FileInput,
  Flex,
  Grid,
  Group,
  MultiSelect,
  Pill,
  PillsInput,
  Text,
  Tooltip,
  Loader,
  Stack,
} from "@mantine/core";
import { type UseFormReturnType } from "@mantine/form";
import {
  IconChevronDown,
  IconFileUpload,
  IconInfoCircle,
} from "@tabler/icons-react";
import { useState, useEffect } from "react";
import StepContentWrapper from "../stepContentWrapper";
import StepperNavigation from "../stepperNavigation";
import type { TargetFormType } from "./types";
import { getAudienceCount, getTargetOptions } from "@/lib/features/notifications/action";
import {
  DEFAULT_ACCOUNT_STATUSES,
  DEFAULT_ACCOUNT_TYPES,
  REGION_SELECT_DATA,
  countriesInRegions,
  optionValuesByLabel,
} from "@/lib/features/notifications/targetDefaults";

const TargetForm: React.FC<{
  activeStep: number;
  setActiveStep: React.Dispatch<React.SetStateAction<number>>;
  accountTypes: CoreMemberAccountType[];
  form: UseFormReturnType<
    TargetFormType,
    (values: TargetFormType) => TargetFormType
  >;
  setAudienceCount: (count: number | null) => void;
  /** False when duplicating an existing campaign — its own criteria win. */
  applyDefaults: boolean;
  /**
   * Tracked by the parent, not here: the Stepper unmounts this step whenever
   * the user moves to another one, so a local flag would re-apply the defaults
   * every time they came back and undo any removals they'd made.
   */
  defaultsApplied: boolean;
  onDefaultsApplied: () => void;
}> = ({
  activeStep,
  setActiveStep,
  accountTypes,
  form,
  setAudienceCount,
  applyDefaults,
  defaultsApplied,
  onDefaultsApplied,
}) => {
  const handleSubmit = (data: TargetFormType) => {
    setActiveStep((current) => (current < 4 ? current + 1 : current));
  };
  const formattedMembershipTypes = accountTypes.map((item) => ({
    ...item,
    label: item.name,
    value: item.id,
  }));

  const [selectedCSVFile, setSelectedCSVFile] = useState<File | null>(null);

  const onMemberChange = (e: React.KeyboardEvent<HTMLInputElement>) => {
    const input = e.currentTarget.value.trim();
    if (
      e.key === "Enter" ||
      e.key === "," ||
      e.key === " " ||
      e.code === "Space"
    ) {
      e.preventDefault();
      if (!input) return;
      const memberNumberRegex = /^\d{7}$/;

      const isEmail = EmailRegex.test(input);
      const isNumericCode = memberNumberRegex.test(input);

      if (!isEmail && !isNumericCode) {
        form.setFieldError("members", "Enter a valid email or 7-digit code");
        return;
      }
      form.clearFieldError("members");
      if (!form.values.members.includes(input)) {
        form.setFieldValue("members", [...form.values.members, input]);
      }
      e.currentTarget.value = "";
    }
  };

  const handleMemberCsv = (file: File | null) => {
    if (!file) return;
    setSelectedCSVFile(file);
    const reader = new FileReader();
    reader.onload = (event) => {
      const text = event.target?.result;
      if (typeof text === "string") {
        // robust splitting by newline (all types) and commas
        const rawItems = text.split(/[\r\n,]+/).map((row) => row.trim());
        const newMembers: string[] = [];
        const memberNumberRegex = /^\d{7}$/;

        rawItems.forEach((member) => {
          if (!member) return;

          const isEmail = EmailRegex.test(member);
          const isNumericCode = memberNumberRegex.test(member);

          if (
            (isEmail || isNumericCode)
          ) {
            newMembers.push(member);
          }
        });

        if (newMembers.length > 0) {
          form.setFieldValue("members", [...form.values.members, ...newMembers]);
        }
        setSelectedCSVFile(null);
      }
    };
    reader.readAsText(file);
  };

  const clearTargetForm = () => {
    form.reset();
  };

  const [loadingCount, setLoadingCount] = useState(false);
  const [localAudienceCount, setLocalAudienceCount] = useState<number | null>(null);

  // Debounce logic for audience count
  useEffect(() => {
    const fetchCount = async () => {
      setLoadingCount(true);
      try {
        const criteria = {
          country: form.values.country,
          city: form.values.city,
          membershipType: form.values.membershipType,
          members: form.values.members,
          userSegment: form.values.userSegment,
          onlyWithValidVersion: form.values.onlyWithValidVersion,
          membershipStatus: form.values.membershipStatus,
        };
        const res = await getAudienceCount(criteria);
        if (res.success && res.data && typeof res.data.count === 'number') {
          setLocalAudienceCount(res.data.count);
          setAudienceCount(res.data.count);
        }
      } catch (e) {
        console.error("Failed to fetch count", e);
      } finally {
        setLoadingCount(false);
      }
    };

    const timeoutId = setTimeout(() => {
      fetchCount();
    }, 1000);

    return () => clearTimeout(timeoutId);
  }, [form.values.country, form.values.city, form.values.membershipType, form.values.members, form.values.userSegment, form.values.onlyWithValidVersion, form.values.membershipStatus]);

  const [cities, setCities] = useState<string[]>([]);
  const [membershipTypesOptions, setMembershipTypesOptions] = useState<any[]>(formattedMembershipTypes);
  const [membershipStatusesOptions, setMembershipStatusesOptions] = useState<any[]>([]);
  const [availableCountries, setAvailableCountries] = useState<string[]>([]);
  const [optionsLoaded, setOptionsLoaded] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const res = await getTargetOptions(form.values.country);
        console.log(res, "res");

        if (res.success && res.data) {
          if (res.data.cities) {
            setCities(res.data.cities);
          }
          if (res.data.countries && res.data.countries.length > 0) {
            setAvailableCountries(res.data.countries);
          }
          if (res.data.membershipTypes) {
            const types = res.data.membershipTypes.map((item: any) => ({
              ...item,
              label: item.name,
              value: String(item.id),
            }));
            setMembershipTypesOptions(types);
            setOptionsLoaded(true);
          }
          if (res.data.membershipStatuses) {
            const statuses = res.data.membershipStatuses.map((item: any) => ({
              ...item,
              label: item.name,
              value: String(item.id),
            }));
            setMembershipStatusesOptions(statuses);
          }
        }
      } catch (error) {
        console.error("Failed to fetch target options:", error);
      }
    };

    fetchData();
  }, [form.values.country]);

  // Pre-select the Account Type / Account Status the business uses on almost
  // every campaign. Applied once per composer session and only to fields the
  // user hasn't already filled, so the selections stay removable.
  useEffect(() => {
    if (!applyDefaults || defaultsApplied) return;
    // Must wait for the options API, not just for a non-empty list: the type
    // options are seeded from the `accountTypes` prop, whose ids belong to a
    // different table than the `membership_type_id` the audience query filters
    // on. Applying defaults off the seed would preselect ids that match nothing.
    if (!optionsLoaded) return;

    const current = form.getValues();
    if (!current.membershipType?.length) {
      form.setFieldValue(
        "membershipType",
        optionValuesByLabel(DEFAULT_ACCOUNT_TYPES, membershipTypesOptions),
      );
    }
    if (membershipStatusesOptions.length > 0 && !current.membershipStatus?.length) {
      form.setFieldValue(
        "membershipStatus",
        optionValuesByLabel(DEFAULT_ACCOUNT_STATUSES, membershipStatusesOptions),
      );
    }
    onDefaultsApplied();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [applyDefaults, defaultsApplied, optionsLoaded, membershipTypesOptions, membershipStatusesOptions]);

  // Mirrored in local state because the form runs in uncontrolled mode — reading
  // `form.values` during render wouldn't re-render this field on change.
  const [selectedRegions, setSelectedRegions] = useState<string[]>(
    () => form.getValues().region || [],
  );

  // Regions add and remove their own countries rather than replacing the whole
  // country selection, so countries picked by hand survive a region change.
  const handleRegionChange = (regions: string[]) => {
    const previous = selectedRegions;
    const removed = previous.filter((r) => !regions.includes(r));
    const added = regions.filter((r) => !previous.includes(r));

    const dropped = new Set(countriesInRegions(removed, availableCountries));
    const kept = (form.getValues().country || []).filter((c) => !dropped.has(c));
    const next = Array.from(new Set([...kept, ...countriesInRegions(added, availableCountries)]));

    setSelectedRegions(regions);
    form.setFieldValue("region", regions);
    form.setFieldValue("country", next);
  };

  return (
    <StepContentWrapper title="Step 2 - Target" onClearClick={clearTargetForm}>
      <form
        onSubmit={form.onSubmit(handleSubmit)}
        style={{
          flex: 1,
          display: "flex",
          flexDirection: "column",
          justifyContent: "space-between",
          gap: "32px",
        }}
      >
        <Grid gutter={"lg"}>
          <Grid.Col span={12}>
            <Stack gap="xs">
              <Checkbox.Group
                label="User Segment"
                fz={14}
                labelProps={{ fz: 13, mb: 5 }}
                errorProps={{ mt: 3 }}
                key={form.key("userSegment")}
                {...form.getInputProps("userSegment")}
              >
                <Group mt="xs">
                  <Checkbox value="android" label="Android" color={"blue.5"} />
                  <Checkbox value="ios" label="IOS" color={"blue.5"} />
                  <Checkbox value="web" label="Web" color={"blue.5"} />
                </Group>
              </Checkbox.Group>
            </Stack>
          </Grid.Col>
          <Grid.Col span={12}>
            <Group justify="space-between" mb={5}>
              <Tooltip label="Selecting a region ticks every country in it that exists in the member database. Countries stay editable below.">
                <Flex gap={5} align="center">
                  <Text fz={13} fw={500}>Region</Text>
                  <IconInfoCircle size={16} />
                </Flex>
              </Tooltip>
              {selectedRegions.length > 0 && (
                <Button
                  variant="subtle"
                  size="compact-xs"
                  onClick={() => handleRegionChange([])}
                >
                  Clear All
                </Button>
              )}
            </Group>
            <MultiSelect
              fz={14}
              placeholder="Pick value"
              data={REGION_SELECT_DATA}
              // Regions resolve against the country list from the member DB, so
              // picking one before it loads would silently select nothing.
              disabled={availableCountries.length === 0}
              searchable
              nothingFoundMessage="Nothing found..."
              rightSection={<IconChevronDown height={18} width={18} />}
              rightSectionProps={{
                style: {
                  borderLeft: "1px solid var(--mantine-color-grey-12)",
                  marginBlock: "6px",
                },
              }}
              value={selectedRegions}
              onChange={handleRegionChange}
            />
          </Grid.Col>
          <Grid.Col span={12}>
            <Group justify="space-between" mb={5}>
              <Text fz={13} fw={500}>Country</Text>
              <Button
                variant="subtle"
                size="compact-xs"
                onClick={() => {
                  const all = availableCountries;
                  const current = form.values.country;
                  form.setFieldValue('country', current.length === all.length ? [] : all);
                }}
              >
                {form.values.country.length === availableCountries.length && availableCountries.length > 0 ? "Deselect All" : "Select All"}
              </Button>
            </Group>
            <MultiSelect
              fz={14}
              placeholder="Pick value"
              data={availableCountries}
              searchable
              nothingFoundMessage="Nothing found..."
              rightSection={<IconChevronDown height={18} width={18} />}
              rightSectionProps={{
                style: {
                  borderLeft: "1px solid var(--mantine-color-grey-12)",
                  marginBlock: "6px",
                },
              }}
              key={form.key("country")}
              {...form.getInputProps("country")}
            />
          </Grid.Col>
          <Grid.Col span={12}>
            <Group justify="space-between" mb={5}>
              <Text fz={13} fw={500}>City</Text>
              <Button
                variant="subtle"
                size="compact-xs"
                onClick={() => {
                  const all = cities;
                  const current = form.values.city;
                  form.setFieldValue('city', current.length === all.length ? [] : all);
                }}
                disabled={cities.length === 0}
              >
                {form.values.city.length === cities.length && cities.length > 0 ? "Deselect All" : "Select All"}
              </Button>
            </Group>
            <MultiSelect
              fz={14}
              placeholder="Pick value"
              data={cities}
              searchable
              nothingFoundMessage="Nothing found..."
              rightSection={<IconChevronDown height={18} width={18} />}
              rightSectionProps={{
                style: {
                  borderLeft: "1px solid var(--mantine-color-grey-12)",
                  marginBlock: "6px",
                },
              }}
              key={form.key("city")}
              {...form.getInputProps("city")}
            />
          </Grid.Col>
          <Grid.Col span={12}>
            <Group justify="space-between" mb={5}>
              <Text fz={13} fw={500}>Account Type</Text>
              <Button
                variant="subtle"
                size="compact-xs"
                onClick={() => {
                  const all = membershipTypesOptions.map(o => o.value);
                  const current = form.values.membershipType;
                  form.setFieldValue('membershipType', current.length === all.length ? [] : all);
                }}
              >
                {form.values.membershipType.length === membershipTypesOptions.length && membershipTypesOptions.length > 0 ? "Deselect All" : "Select All"}
              </Button>
            </Group>
            <MultiSelect
              fz={14}
              placeholder="Pick value"
              data={membershipTypesOptions}
              searchable
              nothingFoundMessage="Nothing found..."
              rightSection={<IconChevronDown height={18} width={18} />}
              rightSectionProps={{
                style: {
                  borderLeft: "1px solid var(--mantine-color-grey-12)",
                  marginBlock: "6px",
                },
              }}
              key={form.key("membershipType")}
              {...form.getInputProps("membershipType")}
            />
          </Grid.Col>
          <Grid.Col span={12}>
            <Group justify="space-between" mb={5}>
              <Text fz={13} fw={500}>Account Status</Text>
              <Button
                variant="subtle"
                size="compact-xs"
                onClick={() => {
                  const all = membershipStatusesOptions.map(o => o.value);
                  const current = form.values.membershipStatus || [];
                  form.setFieldValue('membershipStatus', current.length === all.length ? [] : all);
                }}
              >
                {(form.values.membershipStatus || []).length === membershipStatusesOptions.length && membershipStatusesOptions.length > 0 ? "Deselect All" : "Select All"}
              </Button>
            </Group>
            <MultiSelect
              fz={14}
              placeholder="Pick value"
              data={membershipStatusesOptions}
              searchable
              nothingFoundMessage="Nothing found..."
              rightSection={<IconChevronDown height={18} width={18} />}
              rightSectionProps={{
                style: {
                  borderLeft: "1px solid var(--mantine-color-grey-12)",
                  marginBlock: "6px",
                },
              }}
              key={form.key("membershipStatus")}
              {...form.getInputProps("membershipStatus")}
            />
          </Grid.Col>

          <Grid.Col span={12}>
            <Group justify="space-between" mb={5}>
              <Tooltip label="The selected member number or email address are subjected to above mentioned conditions">
                <Flex gap={5} align={"center"}>
                  <Text fz={13} fw={500}>Member Emails / ID</Text>
                  <IconInfoCircle size={16} />
                </Flex>
              </Tooltip>
              {form.values.members.length > 0 && (
                <Button
                  variant="subtle"
                  size="compact-xs"
                  onClick={() => form.setFieldValue("members", [])}
                >
                  Clear All
                </Button>
              )}
            </Group>
            <Grid align={"end"} gutter={10}>
              <Grid.Col span={9}>
                <PillsInput
                  fz={14}
                  key={form.key("members")}
                  {...form.getInputProps("members")}
                >
                  <Pill.Group>
                    {form.values.members.map((email, index) => (
                      <Pill
                        key={email}
                        withRemoveButton
                        onRemove={() =>
                          form.setFieldValue(
                            "members",
                            form.values.members.filter((_, i) => i !== index),
                          )
                        }
                      >
                        {email}
                      </Pill>
                    ))}
                    <PillsInput.Field
                      placeholder="Enter Comma Separated Member Emails/ID"
                      onKeyDown={onMemberChange}
                    />
                  </Pill.Group>
                </PillsInput>
              </Grid.Col>
              <Grid.Col span={3} pos={"relative"}>
                <FileInput
                  pos={"absolute"}
                  w={"100%"}
                  h={"100%"}
                  top={0}
                  left={0}
                  style={{ zIndex: 10 }}
                  opacity={0}
                  accept=".csv"
                  onChange={handleMemberCsv}
                  value={selectedCSVFile}
                />
                <Button
                  w={"100%"}
                  fz={12}
                  leftSection={<IconFileUpload size={16} />}
                  bg={"dark.1"}
                  c={"dark.11"}
                  fw={500}
                >
                  Upload CSV
                </Button>
              </Grid.Col>
            </Grid>
          </Grid.Col>
        </Grid>

        <Flex gap="md" align="center" bg="gray.1" p="xs" style={{ borderRadius: '8px' }}>
          <Text fw={600} size="sm">Estimated Audience:</Text>
          {loadingCount ? (
            <Loader size="xs" color="blue" />
          ) : (
            <Text fw={700} c="blue">
              {localAudienceCount !== null ? localAudienceCount.toLocaleString() : "0"}
            </Text>
          )}
        </Flex>

        <Flex justify={"end"}>
          <StepperNavigation
            activeStep={activeStep}
            setActiveStep={setActiveStep}
          />
        </Flex>
      </form >
    </StepContentWrapper >
  );
};

export default TargetForm;
