import { forwardRef, memo, useEffect, useImperativeHandle, useState } from "react";
import { useTranslation } from "react-i18next";
import { Alert, Form, type FormInstance, Input, Radio } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import dayjs from "dayjs";
import { z } from "zod";

import Show from "@/components/Show";
import { WORKFLOW_TRIGGERS, type WorkflowNodeConfigForStart, type WorkflowTriggerType, defaultNodeConfigForStart } from "@/domain/workflow";
import { useAntdForm } from "@/hooks";
import { getNextCronExecutions, validCronExpression } from "@/utils/cron";

type StartNodeConfigFormFieldValues = Partial<WorkflowNodeConfigForStart>;

export type StartNodeConfigFormProps = {
  className?: string;
  style?: React.CSSProperties;
  disabled?: boolean;
  initialValues?: StartNodeConfigFormFieldValues;
  onValuesChange?: (values: StartNodeConfigFormFieldValues) => void;
};

export type StartNodeConfigFormInstance = {
  getFieldsValue: () => ReturnType<FormInstance<StartNodeConfigFormFieldValues>["getFieldsValue"]>;
  resetFields: FormInstance<StartNodeConfigFormFieldValues>["resetFields"];
  validateFields: FormInstance<StartNodeConfigFormFieldValues>["validateFields"];
};

const initFormModel = (): StartNodeConfigFormFieldValues => {
  return defaultNodeConfigForStart();
};

const StartNodeConfigForm = forwardRef<StartNodeConfigFormInstance, StartNodeConfigFormProps>(
  ({ className, style, disabled, initialValues, onValuesChange }, ref) => {
    const { t } = useTranslation();

    const formSchema = z
      .object({
        trigger: z.string({ message: t("workflow_node.start.form.trigger.placeholder") }).min(1, t("workflow_node.start.form.trigger.placeholder")),
        triggerCron: z.string().nullish(),
      })
      .superRefine((data, ctx) => {
        if (data.trigger !== WORKFLOW_TRIGGERS.AUTO) {
          return;
        }

        if (!validCronExpression(data.triggerCron!)) {
          ctx.addIssue({
            code: z.ZodIssueCode.custom,
            message: t("workflow_node.start.form.trigger_cron.errmsg.invalid"),
            path: ["triggerCron"],
          });
        }
      });
    const formRule = createSchemaFieldRule(formSchema);
    const { form: formInst, formProps } = useAntdForm({
      name: "workflowNodeStartConfigForm",
      initialValues: initialValues ?? initFormModel(),
    });

    const fieldTrigger = Form.useWatch<WorkflowTriggerType>("trigger", formInst);
    const fieldTriggerCron = Form.useWatch<string>("triggerCron", formInst);
    const [fieldTriggerCronExpectedExecutions, setFieldTriggerCronExpectedExecutions] = useState<Date[]>([]);
    useEffect(() => {
      setFieldTriggerCronExpectedExecutions(getNextCronExecutions(fieldTriggerCron, 5));
    }, [fieldTriggerCron]);

    const handleTriggerChange = (value: string) => {
      if (value === WORKFLOW_TRIGGERS.AUTO) {
        formInst.setFieldValue("triggerCron", formProps.initialValues?.triggerCron || initFormModel().triggerCron);
      } else {
        formInst.setFieldValue("triggerCron", undefined);
      }

      onValuesChange?.(formInst.getFieldsValue(true));
    };

    const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
      onValuesChange?.(values as StartNodeConfigFormFieldValues);
    };

    useImperativeHandle(ref, () => {
      return {
        getFieldsValue: () => {
          return formInst.getFieldsValue(true);
        },
        resetFields: (fields) => {
          return formInst.resetFields(fields);
        },
        validateFields: (nameList, config) => {
          return formInst.validateFields(nameList, config);
        },
      } as StartNodeConfigFormInstance;
    });

    return (
      <Form className={className} style={style} {...formProps} disabled={disabled} layout="vertical" scrollToFirstError onValuesChange={handleFormChange}>
        <Form.Item
          name="trigger"
          label={t("workflow_node.start.form.trigger.label")}
          rules={[formRule]}
          tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.start.form.trigger.tooltip") }}></span>}
        >
          <Radio.Group onChange={(e) => handleTriggerChange(e.target.value)}>
            <Radio value={WORKFLOW_TRIGGERS.AUTO}>{t("workflow_node.start.form.trigger.option.auto.label")}</Radio>
            <Radio value={WORKFLOW_TRIGGERS.MANUAL}>{t("workflow_node.start.form.trigger.option.manual.label")}</Radio>
          </Radio.Group>
        </Form.Item>

        <Form.Item
          name="triggerCron"
          label={t("workflow_node.start.form.trigger_cron.label")}
          hidden={fieldTrigger !== WORKFLOW_TRIGGERS.AUTO}
          rules={[formRule]}
          tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.start.form.trigger_cron.tooltip") }}></span>}
          extra={
            <Show when={fieldTriggerCronExpectedExecutions.length > 0}>
              <div>
                {t("workflow_node.start.form.trigger_cron.extra")}
                <br />
                {fieldTriggerCronExpectedExecutions.map((date, index) => (
                  <span key={index}>
                    {dayjs(date).format("YYYY-MM-DD HH:mm:ss")}
                    <br />
                  </span>
                ))}
              </div>
            </Show>
          }
        >
          <Input placeholder={t("workflow_node.start.form.trigger_cron.placeholder")} />
        </Form.Item>

        <Show when={fieldTrigger === WORKFLOW_TRIGGERS.AUTO}>
          <Form.Item>
            <Alert type="info" message={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.start.form.trigger_cron.guide") }}></span>} />
          </Form.Item>
        </Show>
      </Form>
    );
  }
);

export default memo(StartNodeConfigForm);
