import {
  Box,
  Container,
  FormControl,
  FormControlLabel,
  Select,
  TextField,
  Autocomplete,
  TextFieldProps,
  Grid,
  FormLabel,
  FormHelperText,
} from "@mui/material"
import { useTranslation } from "react-i18next"
import { DatePicker } from "@mui/x-date-pickers"
import { DateTime } from "luxon"
import MenuItem from "@mui/material/MenuItem"
import Button from "@mui/material/Button"
import Checkbox from "@mui/material/Checkbox"
import SaveIcon from "@mui/icons-material/Save"
import CloseIcon from "@mui/icons-material/Close"
import EditIcon from "@mui/icons-material/Edit"
import { getOrganizerList } from "../../../../services/EventAdminService.ts"
import { EventDetailModel, OrganizerModel } from "../../../../../../shared/EntityTypes.ts"
import ShareEventDialog from "../../pages/EventAdmin/components/ShareEventDialog.tsx"
import { useForm } from "@tanstack/react-form"
import { validateURL } from "./functions.ts"
import { useQuery } from "react-query"
import { useNotifications } from "@toolpad/core/useNotifications"
import TimezoneAutocomplete, { TimezoneOption } from "./components/TimeZoneAutocomplete"
import {
  getUserTimeZone,
  timeZoneOptionGenerator,
} from "./components/TimeZoneAutocomplete/functions.ts"
import { useEffect } from "react"
import { countryCode } from "../../../../../../domain/services/userCountry/userCountryModel.ts"
import { useUserCountryCode } from "../../../../../../domain/services/userCountry/userCountryCodeHook.ts"
import {
  useAllCountries,
  useCountry,
} from "../../../../../../services/countryService/countryHooks.ts"
import CountryFlag from "../../../../../../components/CountryFlag"

/**
 * @property eventDetail an event to be displayed in the form
 * @property canEdit weather the form can be edited
 * @property handleSubmit action to be performed when pressing save. Caution! Remember that handle
 * submit must call `event.preventDefault()`.
 * @property handleCancel action to be performed when pressing Cancel button.
 * @property handleEdit action to be performed when pressing Edit button
 */
interface EventAdminFormProps {
  eventDetail?: EventDetailModel
  canEdit?: boolean
  displayIsPublic?: boolean
  autoFillCountry?: boolean
  displayPlaceholders?: boolean
  handleSubmit: (values: EventAdminFormValues) => void
  handleCancel?: () => void
  handleEdit?: () => void
}

export interface EventAdminFormValues {
  description: string
  website?: string
  organizer: OrganizerModel | null
  startDate: DateTime | null
  endDate: DateTime | null
  scope: string
  isPublic: boolean
  timezone: TimezoneOption
  countryCode: countryCode
}

const WEBSITE_MAX_LENGTH = 120
const EVENT_NAME_MAX_LENGTH = 255

/**
 * This is are all the fields that can be set in an event. It can display the data if an event is
 * passed in its props. Data can be edited if an event is passed and canEdit is set to true. In this
 * case, the handleSubmit can update the data on the server. If no data provided, it can be used to
 * create a new event. Caution! Please note that handle submit must call `event.preventDefault()`.
 * @param props
 */
export default function EventAdminForm(props: EventAdminFormProps) {
  const { t, i18n } = useTranslation()
  const notifications = useNotifications()

  const form = useForm({
    defaultValues: {
      description: props.eventDetail?.description ?? "",
      website: props.eventDetail?.website ?? "",
      organizer: props.eventDetail?.organizer || null,
      startDate: props.eventDetail ? DateTime.fromSQL(props.eventDetail.initial_date) : null,
      endDate: props.eventDetail ? DateTime.fromSQL(props.eventDetail.final_date) : null,
      scope: props.eventDetail?.scope ?? "",
      isPublic: props.eventDetail ? !props.eventDetail.is_hidden : false,
      timezone: timeZoneOptionGenerator(
        props.eventDetail?.timezone ?? getUserTimeZone(),
        i18n.language,
      ),
      countryCode: props.eventDetail?.country_code ?? "",
    },
    onSubmit: ({ value }) => props.handleSubmit(value),
  })

  const organizersQuery = useQuery(
    ["organizers"], // Query key
    () => getOrganizerList(),
    {
      staleTime: Infinity,
      enabled: props.canEdit,
      onError: (error) => {
        console.error(error)
        notifications.show(t("EventAdmin.FailedToLoadOrganizers"), {
          severity: "error",
          autoHideDuration: 3000,
        })
      },
    },
  )

  // Country
  const localizedCountries = useAllCountries()
  const countryT = useCountry()

  /// Autofill country
  //// Gather current country
  const { data: currentCountryCode, isLoading: isLoadingCurrentCountryCode } = useUserCountryCode({
    enabled: props.autoFillCountry ?? false,
  })
  //// Update current country
  useEffect(() => {
    if (
      props.autoFillCountry &&
      currentCountryCode &&
      !form.getFieldValue("countryCode") // don’t overwrite user input
    ) {
      form.setFieldValue("countryCode", currentCountryCode)
    }
  }, [currentCountryCode, props.autoFillCountry, form])

  // Style
  const style_props: TextFieldProps = {
    variant: "outlined",
    disabled: !props.canEdit,
  }

  // Re-run isPublic validation on event detail updates
  useEffect(() => {
    void form.validateField("isPublic", "submit")
  }, [form, props.eventDetail])

  // Actual component
  return (
    <Container
      component="form"
      onSubmit={(e) => {
        e.preventDefault()
        e.stopPropagation()
        void form.handleSubmit()
      }}
      disableGutters
      sx={{ p: 4, borderRadius: 3, backgroundColor: "white" }}
    >
      <Grid container spacing={2}>
        <Grid size={{ xs: 12, md: 12 }}>
          <form.Field
            name={"description"}
            validators={{
              onBlur: ({ value }) => (!value ? t("ThisFieldIsRequiredMsg") : undefined),
              onChange: ({ value }) =>
                !value
                  ? undefined
                  : value.length > EVENT_NAME_MAX_LENGTH
                    ? t("EventAdmin.TooLongDescriptionMsg", { count: EVENT_NAME_MAX_LENGTH })
                    : undefined,
            }}
          >
            {(field) => (
              <>
                <FormLabel required error={!!field.state.meta.errors.length}>
                  {t("EventAdmin.EventName")}
                </FormLabel>
                <TextField
                  required
                  fullWidth
                  value={field.state.value}
                  placeholder={
                    props.displayPlaceholders ? t("EventAdmin.EventNamePlaceholder") : undefined
                  }
                  onChange={(e) => field.handleChange(e.target.value)}
                  onBlur={field.handleBlur}
                  error={!!field.state.meta.errors.length}
                  helperText={field.state.meta.errors.join(" ")}
                  {...style_props}
                />
              </>
            )}
          </form.Field>
        </Grid>
        <Grid size={{ xs: 12, md: 12 }}>
          <form.Field
            name={"website"}
            validators={{
              onChange: ({ value }) =>
                value
                  ? value.length > WEBSITE_MAX_LENGTH
                    ? t("EventAdmin.TooLongMsg", { count: WEBSITE_MAX_LENGTH })
                    : undefined
                  : undefined,
              onBlur: ({ value }) =>
                value
                  ? validateURL(value)
                    ? undefined
                    : t("EventAdmin.InvalidURLMsg")
                  : undefined,
            }}
          >
            {(field) => (
              <>
                <FormLabel error={!!field.state.meta.errors.length}>
                  {t("EventAdmin.Website")}
                </FormLabel>
                <TextField
                  fullWidth
                  id="website"
                  name="website"
                  {...style_props}
                  autoComplete="url"
                  value={field.state.value}
                  placeholder={
                    props.displayPlaceholders ? t("EventAdmin.WebsitePlaceholder") : undefined
                  }
                  onBlur={field.handleBlur}
                  onChange={(e) => {
                    field.handleChange(e.target.value)
                  }}
                  error={!!field.state.meta.errors.length}
                  helperText={field.state.meta.errors.join(" ")}
                />
              </>
            )}
          </form.Field>
        </Grid>
        <Grid size={{ xs: 12, md: 6 }}>
          <form.Field name={"organizer"}>
            {(field) => (
              <>
                <FormLabel required>{t("EventAdmin.Organizer")}</FormLabel>
                <Autocomplete<OrganizerModel, false, false, false>
                  fullWidth
                  id="organizer"
                  value={field.state.value}
                  onChange={(_, newOrganizer) => field.handleChange(newOrganizer)}
                  disabled={style_props.disabled}
                  loading={organizersQuery.isLoading}
                  options={organizersQuery.isSuccess ? organizersQuery.data?.data : []}
                  getOptionLabel={(option) => option.name || ""}
                  renderInput={(params) => (
                    <>
                      <TextField
                        {...params}
                        placeholder={
                          props.displayPlaceholders
                            ? t("EventAdmin.OrganizerPlaceholder")
                            : undefined
                        }
                        required
                        {...style_props}
                      />
                    </>
                  )}
                  isOptionEqualToValue={(option, value) => option.id === value.id}
                />
              </>
            )}
          </form.Field>
        </Grid>
        <Grid size={{ xs: 12, md: 3 }}>
          <form.Field
            name={"startDate"}
            validators={{
              onChangeListenTo: ["endDate"],
              onChange: ({ value }) => {
                const endDate = form.getFieldValue("endDate")

                if (endDate && value && endDate < value) {
                  return t("EventAdmin.StartMustBeAfterEnd")
                }
                return undefined
              },
            }}
          >
            {(field) => {
              const error = field.state.meta.errors.join(" ")

              return (
                <FormControl fullWidth error={!!error}>
                  <FormLabel required>{t("EventAdmin.StartDate")}</FormLabel>
                  <DatePicker
                    name={"startDate"}
                    disabled={style_props.disabled}
                    slotProps={{
                      textField: {
                        variant: "outlined",
                        disabled: style_props.disabled,
                        fullWidth: true,
                        required: true,
                      },
                    }}
                    value={field.state.value}
                    onChange={(date) => field.handleChange(date)}
                  />
                  {error ? <FormHelperText>{error}</FormHelperText> : null}
                </FormControl>
              )
            }}
          </form.Field>
        </Grid>
        <Grid size={{ xs: 12, md: 3 }}>
          <form.Field
            name={"endDate"}
            validators={{
              onChangeListenTo: ["startDate"],
              onChange: ({ value }) => {
                const startDate = form.getFieldValue("startDate")

                if (startDate && value && startDate > value) {
                  return t("EventAdmin.EndMustBeBeforeEnd")
                }
                return undefined
              },
            }}
          >
            {(field) => {
              const error = field.state.meta.errors.join(" ")

              return (
                <FormControl fullWidth error={!!error}>
                  <FormLabel required>{t("EventAdmin.FinishDate")}</FormLabel>
                  <DatePicker
                    name={"endDate"}
                    disabled={style_props.disabled}
                    slotProps={{
                      textField: {
                        variant: "outlined",
                        disabled: style_props.disabled,
                        fullWidth: true,
                        required: true,
                      },
                    }}
                    value={field.state.value}
                    onChange={(date) => {
                      field.handleChange(date)
                    }}
                  />
                  {error ? <FormHelperText>{error}</FormHelperText> : null}
                </FormControl>
              )
            }}
          </form.Field>
        </Grid>
        <Grid size={{ xs: 12, md: 4 }}>
          <form.Field name={"scope"}>
            {(field) => (
              <>
                <FormLabel required>{t("EventAdmin.Scopes.Scope")}</FormLabel>
                <FormControl fullWidth required disabled={style_props.disabled}>
                  <Select
                    id="scope"
                    name={"scope"}
                    labelId="scope-label"
                    value={field.state.value}
                    onChange={(e) => {
                      field.handleChange(e.target.value)
                    }}
                    displayEmpty
                    renderValue={(selected) => {
                      if (!selected) {
                        if (props.displayPlaceholders) {
                          return (
                            <span style={{ color: "#888" }}>
                              {t("EventAdmin.Scopes.Placeholder")}
                            </span>
                          )
                        } else {
                          return ""
                        }
                      }
                      const map: Record<string, string> = {
                        int: t("EventAdmin.Scopes.International"),
                        nat: t("EventAdmin.Scopes.National"),
                        "r.h": t("EventAdmin.Scopes.RegionalHigh"),
                        "r.l": t("EventAdmin.Scopes.RegionalLow"),
                        loc: t("EventAdmin.Scopes.Local"),
                        clu: t("EventAdmin.Scopes.Club"),
                      }
                      return map[selected] || ""
                    }}
                  >
                    <MenuItem value={"int"}>{t("EventAdmin.Scopes.International")}</MenuItem>
                    <MenuItem value={"nat"}>{t("EventAdmin.Scopes.National")}</MenuItem>
                    <MenuItem value={"r.h"}>{t("EventAdmin.Scopes.RegionalHigh")}</MenuItem>
                    <MenuItem value={"r.l"}>{t("EventAdmin.Scopes.RegionalLow")}</MenuItem>
                    <MenuItem value={"loc"}>{t("EventAdmin.Scopes.Local")}</MenuItem>
                    <MenuItem value={"clu"}>{t("EventAdmin.Scopes.Club")}</MenuItem>
                  </Select>
                </FormControl>
              </>
            )}
          </form.Field>
        </Grid>
        <Grid size={{ xs: 12, md: 4 }}>
          <form.Field name={"timezone"}>
            {(field) => (
              <>
                <FormLabel required>{t("TimeZone")}</FormLabel>
                <TimezoneAutocomplete
                  value={field.state.value}
                  onChange={field.handleChange}
                  disabled={style_props.disabled}
                />
              </>
            )}
          </form.Field>
        </Grid>
        <Grid size={{ xs: 12, md: 4 }}>
          <form.Field
            name={"countryCode"}
            validators={{
              onSubmit: ({ value }) =>
                value && value !== "" ? undefined : t("ThisFieldIsRequiredMsg"),
            }}
          >
            {(field) => {
              const error = field.state.meta.errors.join(" ")

              return (
                <>
                  <FormLabel required error={!!error}>
                    {t("EventAdmin.Country")}
                  </FormLabel>
                  <Autocomplete
                    id={"countryCode"}
                    fullWidth
                    autoComplete={false}
                    options={localizedCountries.map((country) => country.code)}
                    disableClearable
                    value={field.state.value}
                    onChange={(_, newCountry) => field.handleChange(newCountry ?? "")}
                    loading={isLoadingCurrentCountryCode}
                    disabled={style_props.disabled}
                    renderOption={(props, option) => {
                      const countryName = countryT(option) || option
                      const lowercaseCode = option.toLowerCase()

                      return (
                        <Box
                          component="li"
                          sx={{ "& > picture": { mr: 2, flexShrink: 0 } }}
                          {...props}
                        >
                          <picture>
                            <source
                              type="image/webp"
                              srcSet={`https://flagcdn.com/w20/${lowercaseCode}.webp, https://flagcdn.com/w40/${lowercaseCode}.webp 2x`}
                            />
                            <source
                              type="image/png"
                              srcSet={`https://flagcdn.com/w20/${lowercaseCode}.png, https://flagcdn.com/w40/${lowercaseCode}.png 2x`}
                            />
                            <img
                              src={`https://flagcdn.com/w20/${lowercaseCode}.png`}
                              width={20}
                              alt={`${countryName} flag`}
                              loading="lazy"
                            />
                          </picture>
                          {countryName}
                        </Box>
                      )
                    }}
                    getOptionLabel={(option) => countryT(option) || option}
                    renderInput={(params) => {
                      const value = field.state.value
                      const code = value?.toLowerCase()
                      // MUI v9 dropped the legacy `InputProps` field from
                      // AutocompleteRenderInputParams — only `slotProps.input`
                      // exists now. Destructure `slotProps` out of `params` so
                      // we don't spread a stale slotProps object onto TextField
                      // and then immediately clobber it below; merge our
                      // startAdornment into the one Autocomplete gave us so we
                      // keep whatever ref/endAdornment/etc. it needs internally.
                      const { slotProps, ...restParams } = params

                      return (
                        <TextField
                          {...restParams}
                          error={!!error}
                          slotProps={{
                            ...slotProps,
                            input: {
                              ...slotProps?.input,
                              startAdornment: value ? (
                                <CountryFlag
                                  code={code}
                                  disabled={style_props.disabled}
                                  slotProps={{ picture: { marginRight: 4, marginLeft: 6 } }}
                                />
                              ) : null,
                            },
                          }}
                        />
                      )
                    }}
                  />
                  {error ? <FormHelperText error={!!error}>{error}</FormHelperText> : null}
                </>
              )
            }}
          </form.Field>
        </Grid>
        <Grid
          size={{ xs: 12, md: 4 }}
          sx={{
            display: "flex",
            flexDirection: "row",
            justifyContent: "flex-start",
            alignItems: "center",
          }}
        >
          <form.Field
            name={"isPublic"}
            validators={{
              onSubmit: ({ value }) => {
                if (value && props.eventDetail?.stages.length == 0) {
                  return t("EventAdmin.CannotBePublicWithoutStages")
                }
                return undefined
              },
            }}
          >
            {(field) => {
              const error = field.state.meta.errors?.join(" ")

              return (
                <FormControl fullWidth error={!!error}>
                  <FormControlLabel
                    id={"isPublic"}
                    name={"isPublic"}
                    control={
                      <Checkbox
                        onChange={(e) => {
                          field.handleChange(e.target.checked)
                        }}
                        checked={field.state.value}
                      />
                    }
                    label={t("EventAdmin.Public")}
                    disabled={!props.canEdit}
                    sx={{
                      display: props.displayIsPublic ? undefined : "none",
                    }}
                  />
                  {error ? <FormHelperText error={!!error}>{error}</FormHelperText> : null}
                </FormControl>
              )
            }}
          </form.Field>
        </Grid>
      </Grid>
      <Grid size={{ xs: 12, md: 12, lg: 12 }}>
        <Box
          sx={{
            display: "flex",
            flexDirection: "row",
            justifyContent: "flex-end",
            gap: "1em",
            marginTop: "24px",
          }}
        >
          <>
            {props.eventDetail ? (
              <ShareEventDialog
                eventId={props.eventDetail.id}
                eventName={props.eventDetail.description}
              />
            ) : (
              <></>
            )}
            {props.canEdit ? (
              <>
                <Button
                  variant="outlined"
                  startIcon={<CloseIcon />}
                  onClick={(e) => {
                    e.preventDefault()
                    form.reset()
                    if (props.handleCancel) {
                      props.handleCancel()
                    }
                  }}
                >
                  {t("Cancel")}
                </Button>
                <Button type="submit" variant="contained" startIcon={<SaveIcon />}>
                  {t("common:save")}
                </Button>
              </>
            ) : (
              <Button variant="contained" startIcon={<EditIcon />} onClick={props.handleEdit}>
                {t("common:edit")}
              </Button>
            )}
          </>
        </Box>
      </Grid>
    </Container>
  )
}
