"use client"

import * as React from "react"
import { useTranslation } from "react-i18next"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { Spinner } from "@/components/ui/spinner"
import { Field, FieldContent, FieldDescription, FieldError, FieldLabel } from "@/components/ui/field"
import { Switch } from "@/components/ui/switch"
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"
import { DateTimePicker } from "@/components/datetime-picker"
import { useMessage } from "@/lib/feedback/message"
import { useAccessKeys } from "@/hooks/use-access-keys"
import { useApi } from "@/contexts/api-context"
import { makeRandomString } from "@/lib/functions"
import { cn } from "@/lib/utils"

interface AccessKeysNewItemProps {
  visible: boolean
  onVisibleChange: (visible: boolean) => void
  onSuccess: () => void
  onNotice: (data: unknown) => void
}

export function AccessKeysNewItem({ visible, onVisibleChange, onSuccess, onNotice }: AccessKeysNewItemProps) {
  const { t } = useTranslation()
  const message = useMessage()
  const api = useApi()
  const { createServiceAccount } = useAccessKeys()

  const [accessKey, setAccessKey] = React.useState("")
  const [secretKey, setSecretKey] = React.useState("")
  const [name, setName] = React.useState("")
  const [description, setDescription] = React.useState("")
  const [expiry, setExpiry] = React.useState<string | null>(null)
  const [policy, setPolicy] = React.useState("")
  const [impliedPolicy, setImpliedPolicy] = React.useState(true)
  const [submitting, setSubmitting] = React.useState(false)
  const [submitError, setSubmitError] = React.useState("")
  const [errors, setErrors] = React.useState({
    accessKey: "",
    secretKey: "",
    name: "",
  })

  const minExpiry = React.useMemo(() => new Date().toISOString(), [])

  React.useEffect(() => {
    if (visible) {
      try {
        setAccessKey(makeRandomString(20))
        setSecretKey(makeRandomString(40))
      } catch {
        setAccessKey("")
        setSecretKey("")
        message.error(t("Failed to generate secure random keys"))
      }
      setName("")
      setDescription("")
      setExpiry(null)
      setImpliedPolicy(true)
      setErrors({ accessKey: "", secretKey: "", name: "" })
      setSubmitError("")
      api
        .get("/accountinfo")
        .then((userInfo: { policy?: unknown; Policy?: unknown }) => {
          const rawPolicy = userInfo.policy ?? userInfo.Policy ?? {}

          if (typeof rawPolicy === "string") {
            try {
              const parsed = JSON.parse(rawPolicy)
              setPolicy(JSON.stringify(parsed, null, 2))
            } catch {
              setPolicy(rawPolicy)
            }
          } else {
            setPolicy(JSON.stringify(rawPolicy ?? {}, null, 2))
          }
        })
        .catch(() => {
          setPolicy("{}")
        })
    }
  }, [visible, api, message, t])

  const closeModal = () => {
    onVisibleChange(false)
  }

  const handleOpenChange = (nextVisible: boolean) => {
    if (!submitting || nextVisible) {
      onVisibleChange(nextVisible)
    }
  }

  const validate = () => {
    const newErrors = { accessKey: "", secretKey: "", name: "" }
    if (!accessKey) {
      newErrors.accessKey = t("Please enter Access Key")
    } else if (accessKey.length < 3 || accessKey.length > 20) {
      newErrors.accessKey = t("Access Key length must be between 3 and 20 characters")
    } else if (/\s/.test(accessKey)) {
      newErrors.accessKey = t("Access Key cannot contain spaces")
    }
    if (!secretKey) {
      newErrors.secretKey = t("Please enter Secret Key")
    } else if (secretKey.length < 8 || secretKey.length > 40) {
      newErrors.secretKey = t("Secret Key length must be between 8 and 40 characters")
    }
    if (!name) {
      newErrors.name = t("Please enter name")
    } else if (name.length > 32) {
      newErrors.name = t("Name must be at most 32 characters")
    } else if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(name)) {
      newErrors.name = t(
        "Name can only contain letters, numbers, underscores and hyphens, and must start with a letter",
      )
    }
    setErrors(newErrors)
    return !newErrors.accessKey && !newErrors.secretKey && !newErrors.name
  }

  // Map a server-side validation error to the field it belongs to, so the
  // message renders directly under the relevant input. Returns false when the
  // error is not field-specific (caller falls back to a general message).
  const applyServerError = (reason: string): boolean => {
    const lowered = reason.toLowerCase()
    if (lowered.includes("access key") && lowered.includes("space")) {
      setErrors((prev) => ({ ...prev, accessKey: t("Access Key cannot contain spaces") }))
      return true
    }
    if (lowered.includes("name must contain only") || lowered.includes("name must start")) {
      setErrors((prev) => ({
        ...prev,
        name: t("Name can only contain letters, numbers, underscores and hyphens, and must start with a letter"),
      }))
      return true
    }
    if (lowered.includes("name must not be longer") || lowered.includes("name is too long")) {
      setErrors((prev) => ({ ...prev, name: t("Name must be at most 32 characters") }))
      return true
    }
    return false
  }

  const submitForm = async () => {
    if (submitting) return
    setSubmitError("")
    if (!validate()) {
      message.error(t("Please fill in the correct format"))
      return
    }

    setSubmitting(true)
    try {
      let customPolicy: string | null = null
      if (!impliedPolicy) {
        try {
          customPolicy = JSON.stringify(JSON.parse(policy || "{}"))
        } catch {
          message.error(t("Policy format invalid"))
          setSubmitting(false)
          return
        }
      }

      const payload = {
        accessKey,
        secretKey,
        name,
        description,
        policy: customPolicy,
        expiration: expiry ? expiry : "9999-01-01T00:00:00.000Z",
      }

      const res = await createServiceAccount(payload)
      message.success(t("Added successfully"))
      onNotice(res)
      closeModal()
      onSuccess()
    } catch (error) {
      console.error(error)
      const reason = error instanceof Error && error.message ? error.message : ""
      const handledByField = reason ? applyServerError(reason) : false
      if (!handledByField) {
        setSubmitError(reason || t("Add failed"))
      }
      message.error(reason || t("Add failed"))
    } finally {
      setSubmitting(false)
    }
  }

  return (
    <Dialog open={visible} onOpenChange={handleOpenChange} disablePointerDismissal={submitting}>
      <DialogContent
        className={cn(
          "max-h-[min(90dvh,52rem)] grid-rows-[auto_minmax(0,1fr)_auto] gap-0 overflow-hidden p-0 sm:max-w-xl",
          !impliedPolicy && "sm:max-w-6xl",
        )}
        aria-busy={submitting}
      >
        <DialogHeader className="border-b px-4 py-3 pe-12">
          <DialogTitle>{t("Create Key")}</DialogTitle>
        </DialogHeader>

        <form
          className="contents"
          onSubmit={(event) => {
            event.preventDefault()
            void submitForm()
          }}
        >
          <div className="min-h-0 overflow-y-auto overscroll-contain p-4">
            <div className="flex flex-col gap-4 lg:min-h-[32rem] lg:flex-row">
              <div
                className={cn(
                  impliedPolicy ? "flex flex-1 flex-col gap-4" : "flex w-full flex-col gap-4 lg:w-72 lg:shrink-0",
                )}
              >
                <Field>
                  <FieldLabel htmlFor="create-access-key">{t("Access Key")}</FieldLabel>
                  <FieldContent>
                    <Input
                      id="create-access-key"
                      name="create-access-key"
                      value={accessKey}
                      onChange={(e) => setAccessKey(e.target.value)}
                      autoComplete="off"
                      spellCheck={false}
                      required
                      disabled={submitting}
                      aria-invalid={Boolean(errors.accessKey)}
                      aria-describedby={errors.accessKey ? "create-access-key-error" : undefined}
                    />
                  </FieldContent>
                  <FieldError id="create-access-key-error">{errors.accessKey}</FieldError>
                </Field>

                <Field>
                  <FieldLabel htmlFor="create-secret-key">{t("Secret Key")}</FieldLabel>
                  <FieldContent>
                    <Input
                      id="create-secret-key"
                      name="create-secret-key"
                      type="password"
                      value={secretKey}
                      onChange={(e) => setSecretKey(e.target.value)}
                      autoComplete="off"
                      spellCheck={false}
                      required
                      disabled={submitting}
                      aria-invalid={Boolean(errors.secretKey)}
                      aria-describedby={errors.secretKey ? "create-secret-key-error" : undefined}
                    />
                  </FieldContent>
                  <FieldError id="create-secret-key-error">{errors.secretKey}</FieldError>
                </Field>

                <Field>
                  <FieldLabel htmlFor="create-expiry">{t("Expiry")}</FieldLabel>
                  <FieldContent>
                    <DateTimePicker
                      id="create-expiry"
                      value={expiry}
                      onChange={setExpiry}
                      min={minExpiry}
                      placeholder={t("Please select expiry date")}
                      disabled={submitting}
                      aria-describedby="create-expiry-description"
                    />
                  </FieldContent>
                  <FieldDescription id="create-expiry-description">
                    {t("empty is indicates permanent validity")}
                  </FieldDescription>
                </Field>

                <Field>
                  <FieldLabel htmlFor="create-name">{t("Name")}</FieldLabel>
                  <FieldContent>
                    <Input
                      id="create-name"
                      name="create-name"
                      value={name}
                      onChange={(e) => setName(e.target.value)}
                      autoComplete="off"
                      spellCheck={false}
                      required
                      disabled={submitting}
                      aria-invalid={Boolean(errors.name)}
                      aria-describedby={errors.name ? "create-name-error" : undefined}
                    />
                  </FieldContent>
                  <FieldError id="create-name-error">{errors.name}</FieldError>
                </Field>

                <Field>
                  <FieldLabel htmlFor="create-description">{t("Description")}</FieldLabel>
                  <FieldContent>
                    <Textarea
                      id="create-description"
                      name="create-description"
                      value={description}
                      onChange={(e) => setDescription(e.target.value)}
                      rows={3}
                      disabled={submitting}
                    />
                  </FieldContent>
                </Field>

                <Field orientation="responsive" className="items-start gap-3 border p-3">
                  <FieldLabel htmlFor="create-implied-policy" className="text-sm font-medium">
                    {t("Use main account policy")}
                  </FieldLabel>
                  <FieldContent className="flex flex-col items-start gap-2 sm:flex-row sm:items-center sm:justify-between sm:gap-3">
                    <p className="text-xs text-muted-foreground">
                      {t("Automatically inherit the main account policy when enabled.")}
                    </p>
                    <Switch
                      id="create-implied-policy"
                      name="create-implied-policy"
                      checked={impliedPolicy}
                      onCheckedChange={setImpliedPolicy}
                      disabled={submitting}
                    />
                  </FieldContent>
                </Field>
              </div>

              {!impliedPolicy && (
                <div className="min-h-[20rem] flex-1 lg:min-h-0">
                  <Field className="h-full">
                    <FieldLabel htmlFor="create-policy">{t("Current user policy")}</FieldLabel>
                    <FieldContent className="h-full">
                      <Textarea
                        id="create-policy"
                        name="create-policy"
                        value={policy}
                        onChange={(e) => setPolicy(e.target.value)}
                        className="min-h-[24rem] font-mono text-xs lg:h-full"
                        spellCheck={false}
                        disabled={submitting}
                      />
                    </FieldContent>
                  </Field>
                </div>
              )}
            </div>
          </div>

          {submitError && (
            <p role="alert" className="px-4 text-sm text-destructive">
              {submitError}
            </p>
          )}

          <DialogFooter className="border-t bg-muted/20 px-4 py-3">
            <Button
              type="button"
              variant="outline"
              className="w-full sm:w-auto"
              onClick={closeModal}
              disabled={submitting}
            >
              {t("Cancel")}
            </Button>
            <Button type="submit" variant="default" className="w-full sm:w-auto" disabled={submitting}>
              {submitting ? (
                <span className="flex items-center gap-2">
                  <Spinner className="size-4" />
                  {t("Submit")}
                </span>
              ) : (
                t("Submit")
              )}
            </Button>
          </DialogFooter>
        </form>
      </DialogContent>
    </Dialog>
  )
}
