import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { zodResolver } from "@hookform/resolvers/zod"
import { useEffect } from "react"
import { FormProvider, useForm } from "react-hook-form"
import { z } from "zod"

import { expect } from "storybook/test"

import { FormInput } from "../Form/FormInput"
import { MaterialIcon } from "../Icons/MaterialIcon"
import type { MaterialIconProps } from "../Icons/MaterialIcon"
import { Typography } from "../Typography"
import { MaterialIconName } from "../Icons/MaterialIcon/generated"

interface FormInputStoryProps {
  label?: string
  labelPosition?: "floating" | "top"
  placeholder?: string
  description?: string
  descriptionIcon?: MaterialIconProps["icon"]
  required?: boolean
  disabled?: boolean
  readOnly?: boolean
  showClearContentIcon?: boolean
  showLeftIcon?: boolean
  showRightIcon?: boolean
  leftIconName?: string
  rightIconName?: string
  showWarning?: boolean
  errorMessage?: string
  defaultValue?: string
  autoComplete?: string
}

function FormInputComponent({
  label = "Label",
  labelPosition = "floating",
  placeholder,
  description,
  descriptionIcon = "info",
  required = false,
  disabled = false,
  readOnly = false,
  showClearContentIcon = false,
  showLeftIcon = false,
  showRightIcon = false,
  leftIconName = "person",
  rightIconName = "lock",
  showWarning = false,
  errorMessage,
  defaultValue = "",
  autoComplete,
}: FormInputStoryProps) {
  const schema = z.object({
    input: errorMessage
      ? z.string().min(1, errorMessage)
      : required
        ? z.string().min(1, "This field is required")
        : z.string().optional(),
  })

  const methods = useForm<{ input: string }>({
    resolver: zodResolver(schema),
    defaultValues: {
      input: defaultValue,
    },
    mode: "onChange",
  })

  useEffect(() => {
    if (errorMessage) {
      methods.setError("input", {
        type: "manual",
        message: errorMessage,
      })
      methods.trigger("input")
    } else {
      methods.clearErrors("input")
    }
  }, [errorMessage, methods])

  const validationState = showWarning ? "warning" : undefined

  return (
    <FormProvider {...methods}>
      <div style={{ padding: "1rem" }}>
        <FormInput
          name="input"
          label={label}
          labelPosition={labelPosition}
          placeholder={placeholder}
          description={description}
          descriptionIcon={descriptionIcon}
          disabled={disabled}
          readOnly={readOnly}
          required={required}
          registerOptions={required ? { required: true } : undefined}
          showClearContentIcon={showClearContentIcon}
          leftIcon={
            showLeftIcon && leftIconName ? (
              <MaterialIcon icon={leftIconName as MaterialIconName} />
            ) : undefined
          }
          rightIcon={
            showRightIcon && rightIconName ? (
              <MaterialIcon icon={rightIconName as MaterialIconName} />
            ) : undefined
          }
          validationState={validationState}
          autoComplete={autoComplete}
        />
      </div>
    </FormProvider>
  )
}

const meta: Meta<typeof FormInputComponent> = {
  title: "Core Components/Input/TextInput",
  component: FormInputComponent,
  argTypes: {
    label: {
      control: "text",
      name: "Label",
      description: "Label text",
      table: {
        type: { summary: "string" },
        order: 1,
      },
    },
    labelPosition: {
      control: "select",
      name: "Label Position",
      options: ["floating", "top"],
      description: "Label position",
      table: {
        type: { summary: "'floating' | 'top'" },
        defaultValue: { summary: "'floating'" },
        order: 2,
      },
    },
    placeholder: {
      control: "text",
      name: "Placeholder",
      description: "Placeholder text",
      table: {
        type: { summary: "string" },
        defaultValue: { summary: "undefined" },
        order: 3,
      },
    },
    description: {
      control: "text",
      name: "Description",
      description: "Helper text (hidden when error is shown)",
      table: {
        type: { summary: "string" },
        defaultValue: { summary: "undefined" },
        order: 4,
      },
    },
    descriptionIcon: {
      control: "select",
      name: "Description Icon",
      options: ["info", "warning", "error"],
      description: "Description icon",
      table: {
        type: { summary: "string" },
        defaultValue: { summary: "'info'" },
        order: 5,
      },
    },
    required: {
      control: "boolean",
      name: "Required",
      description: "Required field",
      table: {
        type: { summary: "boolean" },
        defaultValue: { summary: "false" },
        order: 6,
      },
    },
    disabled: {
      control: "boolean",
      name: "Disabled",
      description: "Disabled state",
      table: {
        type: { summary: "boolean" },
        defaultValue: { summary: "false" },
        order: 7,
      },
    },
    readOnly: {
      control: "boolean",
      name: "Read Only",
      description: "Read-only state",
      table: {
        type: { summary: "boolean" },
        defaultValue: { summary: "false" },
        order: 8,
      },
    },
    showClearContentIcon: {
      control: "boolean",
      name: "Show Clear Icon",
      description: "Show clear button",
      table: {
        type: { summary: "boolean" },
        defaultValue: { summary: "false" },
        order: 9,
      },
    },
    showLeftIcon: {
      control: "boolean",
      name: "Show Left Icon",
      description: "Show left icon",
      table: {
        type: { summary: "boolean" },
        defaultValue: { summary: "false" },
        order: 10,
      },
    },
    leftIconName: {
      control: "select",
      name: "Left Icon",
      options: [
        "calendar_month",
        "credit_card",
        "mail",
        "location_on",
        "info",
        "lock",
        "phone",
        "search",
        "sell",
        "visibility",
        "visibility_off",
      ],
      description: "Left icon name",
      table: {
        type: { summary: "string" },
        defaultValue: { summary: "'person'" },
        order: 11,
      },
    },
    showRightIcon: {
      control: "boolean",
      name: "Show Right Icon",
      description: "Show right icon",
      table: {
        type: { summary: "boolean" },
        defaultValue: { summary: "false" },
        order: 12,
      },
    },
    rightIconName: {
      control: "select",
      name: "Right Icon",
      options: [
        "calendar_month",
        "credit_card",
        "mail",
        "location_on",
        "info",
        "lock",
        "phone",
        "search",
        "sell",
        "visibility",
        "visibility_off",
      ],
      description: "Right icon name",
      table: {
        type: { summary: "string" },
        defaultValue: { summary: "'lock'" },
        order: 13,
      },
    },
    showWarning: {
      control: "boolean",
      name: "Show Warning",
      description: "Warning state",
      table: {
        type: { summary: "boolean" },
        defaultValue: { summary: "false" },
        order: 14,
      },
    },
    errorMessage: {
      control: "text",
      name: "Error Message",
      description: "Error message",
      table: {
        type: { summary: "string" },
        defaultValue: { summary: "undefined" },
        order: 15,
      },
    },
    autoComplete: {
      control: "select",
      name: "Autocomplete",
      description: "HTML autocomplete attribute value",
      options: [
        undefined,
        "name",
        "given-name",
        "family-name",
        "mail",
        "username",
        "tel",
        "tel-national",
        "organization",
        "address-line1",
        "address-line2",
        "city",
        "postal-code",
        "country",
        "off",
      ],
      table: {
        type: { summary: "string" },
        defaultValue: { summary: "undefined" },
        order: 16,
      },
    },
  },
}

export default meta

type Story = StoryObj<typeof FormInputComponent>

export const Default: Story = {
  args: {
    label: "Label",
    labelPosition: "floating",
    placeholder: undefined,
    description: undefined,
    descriptionIcon: "info",
    required: false,
    disabled: false,
    readOnly: false,
    showClearContentIcon: false,
    showLeftIcon: false,
    showRightIcon: false,
    leftIconName: "person",
    rightIconName: "lock",
    showWarning: false,
    errorMessage: undefined,
    autoComplete: undefined,
  },
  play: async ({ canvas, userEvent }) => {
    const textbox = canvas.getByRole("textbox")
    expect(textbox).not.toBeDisabled()

    expect(textbox).toHaveValue("")

    await userEvent.type(textbox, "Hello World")
    expect(textbox).toHaveValue("Hello World")

    await userEvent.clear(textbox)
    expect(textbox).toHaveValue("")
  },
}

// ============================================================================
// Input Variations Showcase
// ============================================================================

const showcaseSchema = z.object({
  default: z.string().optional(),
  placeholder: z.string().optional(),
  filled: z.string().optional(),
  required: z.string().min(1, "This field is required"),
  disabled: z.string().optional(),
  disabledFilled: z.string().optional(),
  warningState: z.string().optional(),
  warningFilled: z.string().optional(),
  emailIcon: z.string().optional(),
  searchIcon: z.string().optional(),
  locked: z.string().optional(),
  bothIcons: z.string().optional(),
  emailIconTop: z.string().optional(),
  searchIconTop: z.string().optional(),
  lockedTop: z.string().optional(),
  bothIconsTop: z.string().optional(),
  emailClear: z.string().optional(),
  searchClear: z.string().optional(),
  clearLeftRight: z.string().optional(),
  emptyClear: z.string().optional(),
  error: z.string().min(10, "Must be at least 10 characters"),
  errorFilled: z.string().email("Invalid email"),
  warning: z.string().optional(),
  warningFilledValidation: z.string().optional(),
  text: z.string().optional(),
  emailType: z.string().optional(),
  telType: z.string().optional(),
  number: z.string().optional(),
  passwordType: z.string().optional(),
  urlType: z.string().optional(),
  combined1: z.string().optional(),
  combined2: z.string().email("Invalid email"),
  combined3: z.string().optional(),
})

type ShowcaseFormData = z.infer<typeof showcaseSchema>

function InputShowcase() {
  const methods = useForm<ShowcaseFormData>({
    resolver: zodResolver(showcaseSchema),
    defaultValues: {
      filled: "Sample text",
      disabledFilled: "Cannot edit",
      warningFilled: "Needs attention",
      emailClear: "user@example.com",
      searchClear: "",
      clearLeftRight: "user@example.com",
      error: "Short",
      errorFilled: "Invalid input",
      warningFilledValidation: "Needs attention",
      combined1: "user@example.com",
      combined2: "Invalid email",
    },
    mode: "onChange",
  })

  // Trigger validation for error examples on mount
  useEffect(() => {
    methods.trigger(["error", "errorFilled", "combined2"])
  }, [methods])

  return (
    <FormProvider {...methods}>
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          gap: "3rem",
          maxWidth: "800px",
          padding: "2rem",
        }}
      >
        {/* Basic States */}
        <section>
          <Typography variant="Title/sm">
            <h2>Basic States</h2>
          </Typography>
          <div
            style={{
              display: "grid",
              gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
              gap: "1.5rem",
              marginTop: "1rem",
            }}
          >
            <FormInput name="default" label="Default" />
            <FormInput
              name="placeholder"
              label="Placeholder"
              placeholder="Enter text here..."
            />
            <FormInput
              name="default2"
              label="Default"
              description="This is a default input with a description"
            />
            <FormInput
              name="default3"
              label="Default"
              placeholder="Enter text here..."
              description="This is a default input with a description"
            />
            <FormInput name="filled" label="Filled" />
            <FormInput
              name="required"
              label="Required"
              registerOptions={{ required: true }}
              hideError
            />
            <FormInput name="disabled" label="Disabled" disabled />
            <FormInput name="disabledFilled" label="Disabled Filled" disabled />
            <FormInput
              name="warningState"
              label="Warning State"
              validationState="warning"
            />
            <FormInput
              name="warningFilled"
              label="Warning with Value"
              validationState="warning"
            />
          </div>
        </section>

        {/* With Icons */}
        <section>
          <Typography variant="Title/sm">
            <h2>With Icons</h2>
          </Typography>
          <div
            style={{
              display: "grid",
              gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
              gap: "1.5rem",
              marginTop: "1rem",
            }}
          >
            <FormInput
              name="emailIcon"
              label="Email"
              type="email"
              leftIcon={<MaterialIcon icon="mail" />}
            />
            <FormInput
              name="searchIcon"
              label="Search"
              leftIcon={<MaterialIcon icon="search" />}
            />
            <FormInput
              name="locked"
              label="Locked icon"
              rightIcon={<MaterialIcon icon="lock" />}
            />
            <FormInput
              name="bothIcons"
              label="With Both Icons"
              leftIcon={<MaterialIcon icon="person" />}
              rightIcon={<MaterialIcon icon="check_circle" />}
            />
          </div>
          <div
            style={{
              display: "grid",
              gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
              gap: "1.5rem",
              marginTop: "1rem",
            }}
          >
            <FormInput
              name="emailIconTop"
              label="Email"
              type="email"
              leftIcon={<MaterialIcon icon="mail" />}
              labelPosition="top"
            />
            <FormInput
              name="searchIconTop"
              label="Search"
              leftIcon={<MaterialIcon icon="search" />}
              labelPosition="top"
            />
            <FormInput
              name="lockedTop"
              label="Locked icon"
              rightIcon={<MaterialIcon icon="lock" />}
              labelPosition="top"
            />
            <FormInput
              name="bothIconsTop"
              label="With Both Icons"
              leftIcon={<MaterialIcon icon="person" />}
              rightIcon={<MaterialIcon icon="check_circle" />}
              labelPosition="top"
            />
          </div>
        </section>

        {/* Clear Button */}
        <section>
          <Typography variant="Title/sm">
            <h2>Clear Button</h2>
          </Typography>
          <div
            style={{
              display: "grid",
              gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
              gap: "1.5rem",
              marginTop: "1rem",
            }}
          >
            <FormInput name="emptyClear" label="Empty" showClearContentIcon />

            <FormInput
              name="emailClear"
              label="Email with Clear"
              type="email"
              showClearContentIcon
            />
            <FormInput
              name="clearLeftRight"
              label="Clear with Left Icon"
              leftIcon={<MaterialIcon icon="mail" />}
              showClearContentIcon
            />
            <FormInput
              name="clearRightIcon"
              label="Clear with Right Icon"
              rightIcon={<MaterialIcon icon="lock" />}
              showClearContentIcon
            />
            <FormInput
              name="clearBothIcons"
              label="Clear with Both Icons"
              leftIcon={<MaterialIcon icon="mail" />}
              rightIcon={<MaterialIcon icon="lock" />}
              showClearContentIcon
            />
          </div>
        </section>

        {/* Validation States */}
        <section>
          <Typography variant="Title/sm">
            <h2>Validation States</h2>
          </Typography>
          <div
            style={{
              display: "grid",
              gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
              gap: "1.5rem",
              marginTop: "1rem",
            }}
          >
            <FormInput
              name="error"
              label="Error State"
              registerOptions={{ minLength: 10 }}
            />
            <FormInput
              name="errorFilled"
              label="Error with Value"
              registerOptions={{ required: true }}
            />
            <FormInput
              name="warning"
              label="Warning State"
              validationState="warning"
            />
            <FormInput
              name="warningFilledValidation"
              label="Warning with Value"
              validationState="warning"
            />
          </div>
        </section>

        {/* Input Types */}
        <section>
          <Typography variant="Title/sm">
            <h2>Input Types</h2>
          </Typography>
          <div
            style={{
              display: "grid",
              gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
              gap: "1.5rem",
              marginTop: "1rem",
            }}
          >
            <FormInput name="text" label="Text" type="text" />
            <FormInput name="emailType" label="Email" type="email" />
            <FormInput name="number" label="Number" type="number" />
          </div>
        </section>
      </div>
    </FormProvider>
  )
}

export const AllVariations: StoryObj<typeof InputShowcase> = {
  render: () => <InputShowcase />,
  parameters: {
    layout: "fullscreen",
  },
}
