import { Alert, App, Checkbox, Divider, Form, Input, Popover, Select, Spin } from "antd";
import { observer } from "mobx-react";
import { useCallback, useState } from "react";

import { PluginUpdateTermFields } from "./terms.js";
import { __, _i } from "../../../utils/i18n.js";
import { LearnMoreTag } from "../../learnMoreTag.js";

import type { PluginUpdate } from "../../../models/pluginUpdate.js";
import type { CSSProperties, ComponentProps, FC, ReactNode } from "react";

const PLUGIN_UPDATE_FORM_LAYOUT = {
    labelCol: { span: 24 },
    wrapperCol: { span: 24 },
};

const PLUGIN_UPDATE_FORM_LAYOUT_MARGIN_BOTTOM: CSSProperties = { marginBottom: 8 };

const PluginUpdateForm: FC<{
    onSave?: () => void;
    onFailure?: () => void;
    footer?: ReactNode;
    pluginUpdate: PluginUpdate;
}> = observer(({ onSave, onFailure, footer, pluginUpdate }) => {
    const { message } = App.useApp();
    const [forceFormValidateStatus, setForceFormValidateStatus] = useState(false);

    const {
        busy,
        slug,
        allowsAutoUpdates,
        needsLicenseKeys,
        licenses,
        unlicensedEntries,
        noUsageEntries,
        modifiableEntries,
        invalidKeysError,
        accountSiteUrl,
        additionalCheckboxes,
        licenseKeyHelpUrl,
        name,
        potentialNewsletterUser: { firstName, email },
        showBlogName,
        showNetworkWideUpdateIssueNotice,
    } = pluginUpdate;

    const allowNoUsage = licenses.length > 1; // only allow "No usage" within multisite

    const initialValues = {
        licenses: licenses.map(({ blog, code, installationType, hint, noUsage }) => ({
            blog,
            code:
                code ||
                // Read a code from the hint
                (hint ? hint.help.match(/(\w{8}-\w{4}-\w{4}-\w{4}-\w{12})|(\w{32})/)?.[0] : "") ||
                "",
            installationType: installationType || "",
            noUsage,
        })),
        autoUpdates: allowsAutoUpdates,
        terms: false,
        telemetry: false,
        newsletter: false,
        firstName,
        email,
        ...additionalCheckboxes.reduce(
            (p, c) => {
                p[c.id] = false;
                return p;
            },
            {} as Record<string, boolean>,
        ),
    };
    const [form] = Form.useForm<typeof initialValues>();
    const [showTermFields, setShowTermFields] = useState(noUsageEntries.length !== unlicensedEntries.length);

    const handleSave = useCallback(
        async (values: typeof initialValues) => {
            const { licenses: formLicenses, ...meta } = values;
            const newMeta = {
                ...meta,
                licenses: JSON.stringify(
                    needsLicenseKeys
                        ? // Remove all entries which are already licensed
                          formLicenses.filter(({ blog }) => {
                              const [foundLicense] = licenses.filter((k) => k.blog === blog);
                              return unlicensedEntries.indexOf(foundLicense) > -1;
                          })
                        : // The free version does not show any inputs for license keys and license activation is done by backend
                          undefined,
                ),
            };

            try {
                await pluginUpdate.update(newMeta);

                form.setFieldsValue({
                    terms: false,
                    telemetry: false,
                    newsletter: false,
                });

                message.success(__("Your license has been activated!"));
                onSave?.();
            } catch (e: any) {
                if (!pluginUpdate.invalidKeysError) {
                    message.error(e.responseJSON.message);
                }
                // No error needed cause it is catch trough `invalidKeysError`
                onFailure?.();
                throw e;
            }
        },
        [pluginUpdate, onSave, licenses, unlicensedEntries, needsLicenseKeys],
    );

    const onFinish: ComponentProps<typeof Form>["onFinish"] = useCallback(
        async (values) => {
            try {
                await handleSave(values as typeof initialValues);
            } catch (e) {
                // Silence is golden.
            } finally {
                setForceFormValidateStatus(false);
            }
        },
        [form, handleSave, setForceFormValidateStatus],
    );

    const onFinishFailed: ComponentProps<typeof Form>["onFinishFailed"] = useCallback(() => {
        setForceFormValidateStatus(true);
        setShowTermFields(true);
    }, []);

    return (
        <Spin spinning={busy}>
            {showNetworkWideUpdateIssueNotice && (
                <div className="notice notice-error inline below-h2 notice-alt" style={{ margin: "0 0 10px 0" }}>
                    <p>
                        {__(
                            "You are using a WordPress mulisite. Due to technical limitations of WordPress core, %s can receive automatic updates in WordPress multisites only if the plugin is enabled network-wide. You can enable the plugin network-wide, but still only license it for specific sites.",
                            name,
                        )}
                    </p>
                    <p>{__("Please enable %s network-wide or take care of regular updates manually!", name)}</p>
                </div>
            )}
            {unlicensedEntries.length > 0 && (
                <>
                    <p className="description" style={{ marginBottom: 15 }}>
                        {needsLicenseKeys
                            ? __("Activate your %s PRO license to receive regular updates and support.", name)
                            : _i(
                                  __(
                                      "To use all advantages of %s {{strong}}you need a free license{{/strong}}. After license activation you will receive answers to support requests and announcements in your plugin (e.g. also notices for discount actions of the PRO version).",
                                      name,
                                  ),
                                  { strong: <strong /> },
                              )}
                    </p>
                    <Form
                        name={`license-form-${slug}`}
                        id={`license-form-${slug}`}
                        form={form}
                        {...PLUGIN_UPDATE_FORM_LAYOUT}
                        initialValues={initialValues}
                        onFinish={onFinish}
                        onFinishFailed={onFinishFailed}
                        onChange={() => {
                            setShowTermFields(true);
                        }}
                        labelWrap
                    >
                        {needsLicenseKeys && (
                            <>
                                <Form.List name="licenses">
                                    {(fields) =>
                                        fields.map((field) => {
                                            const { blog } = form.getFieldValue([
                                                "licenses",
                                                field.name,
                                            ]) as (typeof initialValues)["licenses"][0];
                                            const [foundLicense] = licenses.filter((k) => k.blog === blog);

                                            // Already licensed, do not show in form again
                                            if (unlicensedEntries.indexOf(foundLicense) === -1) {
                                                return null;
                                            }

                                            const {
                                                busy: licenseBusy,
                                                blogName,
                                                programmatically,
                                                host,
                                            } = foundLicense;
                                            const lastBlogPutError = invalidKeysError?.[blog];

                                            // Hints priority: Form handling, POST-Request, Hint coming from license deactivation
                                            const useHint = forceFormValidateStatus
                                                ? ({} as typeof foundLicense.hint)
                                                : lastBlogPutError || foundLicense.hint;

                                            const isLicenseMaxUsagesReached =
                                                !!lastBlogPutError?.debug.errors["LicenseMaxUsagesReached"];

                                            return (
                                                <Spin spinning={licenseBusy} key={field.key}>
                                                    <Form.Item
                                                        noStyle
                                                        shouldUpdate={(prevValues, nextValues) =>
                                                            prevValues.licenses[field.key].noUsage !==
                                                            nextValues.licenses[field.key].noUsage
                                                        }
                                                    >
                                                        {({ getFieldValue }) => {
                                                            const noUsage = getFieldValue([
                                                                "licenses",
                                                                field.key,
                                                                "noUsage",
                                                            ]);

                                                            return (
                                                                <Form.Item
                                                                    label={
                                                                        <span>
                                                                            {unlicensedEntries.length > 1 ||
                                                                            showBlogName
                                                                                ? _i(
                                                                                      __(
                                                                                          "Installation type and license key for {{strong}}%s{{/strong}}",
                                                                                          blogName,
                                                                                      ),
                                                                                      {
                                                                                          strong: <strong />,
                                                                                      },
                                                                                  )
                                                                                : __(
                                                                                      "Installation type and license key",
                                                                                  )}{" "}
                                                                            <LearnMoreTag url={licenseKeyHelpUrl} />
                                                                        </span>
                                                                    }
                                                                    {...useHint}
                                                                    required
                                                                    style={PLUGIN_UPDATE_FORM_LAYOUT_MARGIN_BOTTOM}
                                                                >
                                                                    {!noUsage && (
                                                                        <>
                                                                            <Form.Item
                                                                                name={[field.name, "code"]}
                                                                                noStyle
                                                                                rules={[
                                                                                    {
                                                                                        // Allow UUID format and additionally a custom 32-length string
                                                                                        pattern:
                                                                                            /(^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$)|(^\w{32}$)/,
                                                                                        required: true,
                                                                                        message: __(
                                                                                            "Please enter a valid license key!",
                                                                                        ),
                                                                                    },
                                                                                ]}
                                                                                normalize={(value) => value?.trim()}
                                                                            >
                                                                                <Input
                                                                                    placeholder={
                                                                                        programmatically
                                                                                            ? programmatically.code
                                                                                            : "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
                                                                                    }
                                                                                    disabled={!!programmatically}
                                                                                    addonBefore={
                                                                                        <Popover
                                                                                            destroyTooltipOnHide
                                                                                            overlayStyle={{
                                                                                                maxWidth: "370px",
                                                                                            }}
                                                                                            content={
                                                                                                <div className="wp-clearfix">
                                                                                                    <p
                                                                                                        style={{
                                                                                                            marginTop: 0,
                                                                                                        }}
                                                                                                    >
                                                                                                        {_i(
                                                                                                            __(
                                                                                                                "{{strong}}Production:{{/strong}} Use this, when your site is {{i}}live{{/i}} and {{i}}publicly available{{/i}} to your website visitors.",
                                                                                                            ),
                                                                                                            {
                                                                                                                strong: (
                                                                                                                    <strong />
                                                                                                                ),
                                                                                                                i: (
                                                                                                                    <i />
                                                                                                                ),
                                                                                                            },
                                                                                                        )}
                                                                                                    </p>
                                                                                                    <p>
                                                                                                        {_i(
                                                                                                            __(
                                                                                                                "{{strong}}Development:{{/strong}} Use this, when your site is {{i}}not yet live{{/i}}, or it is a {{i}}staging environment{{/i}} of your site.",
                                                                                                            ),
                                                                                                            {
                                                                                                                strong: (
                                                                                                                    <strong />
                                                                                                                ),
                                                                                                                i: (
                                                                                                                    <i />
                                                                                                                ),
                                                                                                            },
                                                                                                        )}
                                                                                                    </p>
                                                                                                    <p
                                                                                                        style={{
                                                                                                            marginBottom: 0,
                                                                                                        }}
                                                                                                    >
                                                                                                        {__(
                                                                                                            "You can change the installation-type at any time by deactivating the license and activate it again.",
                                                                                                        )}
                                                                                                    </p>
                                                                                                </div>
                                                                                            }
                                                                                            title={
                                                                                                <>
                                                                                                    {__(
                                                                                                        "What is an installation type?",
                                                                                                    )}
                                                                                                    &nbsp;
                                                                                                    <LearnMoreTag
                                                                                                        url={__(
                                                                                                            "https://devowl.io/knowledge-base/license-installation-type/",
                                                                                                        )}
                                                                                                    />
                                                                                                </>
                                                                                            }
                                                                                            placement="topLeft"
                                                                                            trigger="hover"
                                                                                        >
                                                                                            <div>
                                                                                                <Form.Item
                                                                                                    name={[
                                                                                                        field.name,
                                                                                                        "installationType",
                                                                                                    ]}
                                                                                                    noStyle
                                                                                                    rules={[
                                                                                                        {
                                                                                                            required: true,
                                                                                                            message: __(
                                                                                                                "Please choose an installation type!",
                                                                                                            ),
                                                                                                        },
                                                                                                    ]}
                                                                                                >
                                                                                                    <Select
                                                                                                        placeholder={__(
                                                                                                            "Installation type",
                                                                                                        )}
                                                                                                        disabled={
                                                                                                            !!programmatically
                                                                                                        }
                                                                                                    >
                                                                                                        <Select.Option
                                                                                                            value=""
                                                                                                            disabled
                                                                                                        >
                                                                                                            {programmatically
                                                                                                                ? programmatically.type ===
                                                                                                                  "development"
                                                                                                                    ? __(
                                                                                                                          "Development",
                                                                                                                      )
                                                                                                                    : __(
                                                                                                                          "Production",
                                                                                                                      )
                                                                                                                : __(
                                                                                                                      "Select installation type...",
                                                                                                                  )}
                                                                                                        </Select.Option>
                                                                                                        <Select.Option value="production">
                                                                                                            {__(
                                                                                                                "Production",
                                                                                                            )}
                                                                                                        </Select.Option>
                                                                                                        <Select.Option value="development">
                                                                                                            {__(
                                                                                                                "Development",
                                                                                                            )}
                                                                                                        </Select.Option>
                                                                                                    </Select>
                                                                                                </Form.Item>
                                                                                            </div>
                                                                                        </Popover>
                                                                                    }
                                                                                />
                                                                            </Form.Item>
                                                                        </>
                                                                    )}
                                                                    {allowNoUsage && (
                                                                        <Form.Item
                                                                            name={[field.name, "noUsage"]}
                                                                            valuePropName="checked"
                                                                            style={{
                                                                                marginTop: noUsage ? -25 : 0,
                                                                                marginBottom: 0,
                                                                            }}
                                                                        >
                                                                            <Checkbox>
                                                                                {__(
                                                                                    "I do not want to license and use the plugin for this site within my multisite.",
                                                                                )}
                                                                            </Checkbox>
                                                                        </Form.Item>
                                                                    )}
                                                                </Form.Item>
                                                            );
                                                        }}
                                                    </Form.Item>
                                                    {programmatically && (
                                                        <div
                                                            className="notice notice-warning inline below-h2 notice-alt"
                                                            style={{ margin: "0 0 10px 0" }}
                                                        >
                                                            <p>
                                                                {_i(
                                                                    __(
                                                                        "This license cannot be activated manually because it is configured programmatically. That means you have used the {{a}}activation filter{{/a}} for host {{code}}%s{{/code}} (Blog ID: %d). Unfortunately, something went wrong during the license activation.",
                                                                        host,
                                                                        blog,
                                                                    ),
                                                                    {
                                                                        code: <code />,
                                                                        a: (
                                                                            <a
                                                                                href="https://docs.devowl.io/real-cookie-banner/hooks/DevOwl_RealProductManager_License_Programmatic_$slug.html"
                                                                                target="_blank"
                                                                                rel="noreferrer"
                                                                            />
                                                                        ),
                                                                    },
                                                                )}{" "}
                                                                &bull;{" "}
                                                                <a
                                                                    className="button-link"
                                                                    onClick={async () => {
                                                                        try {
                                                                            await foundLicense.retry();

                                                                            if (foundLicense.hint) {
                                                                                message.error(foundLicense.hint.help);
                                                                            }
                                                                        } catch (e) {
                                                                            message.error(
                                                                                (e as any).responseJSON.message,
                                                                            );
                                                                        }
                                                                    }}
                                                                >
                                                                    {__("Retry activation")}
                                                                </a>
                                                            </p>
                                                        </div>
                                                    )}
                                                    {isLicenseMaxUsagesReached && (
                                                        <Alert
                                                            type="info"
                                                            showIcon
                                                            message={__(
                                                                "I have purchased a license that can be used on multiple websites! What can I do?",
                                                            )}
                                                            description={
                                                                <>
                                                                    <p>
                                                                        {_i(
                                                                            __(
                                                                                "After purchasing one of our products, only one license key is generated by default, even if your purchase covers multiple websites. This license key can be used for only one website by default. To add more websites to your purchase, you can generate additional license keys within your quota in the {{a}}Customer Center{{/a}}.",
                                                                            ),
                                                                            {
                                                                                a: (
                                                                                    <a
                                                                                        href={accountSiteUrl}
                                                                                        target="_blank"
                                                                                        rel="noreferrer"
                                                                                    />
                                                                                ),
                                                                            },
                                                                        )}
                                                                    </p>
                                                                    <a
                                                                        className="button button-primary"
                                                                        href={accountSiteUrl}
                                                                        target="_blank"
                                                                        rel="noreferrer"
                                                                    >
                                                                        {__("Add licenses in the customer center now")}
                                                                    </a>
                                                                    &nbsp;
                                                                    <a
                                                                        className="button"
                                                                        target="_blank"
                                                                        href={__(
                                                                            "https://devowl.io/knowledge-base/the-limit-of-activated-clients-for-this-license-has-already-been-reached/",
                                                                        )}
                                                                        rel="noreferrer"
                                                                    >
                                                                        {__("Learn more")}
                                                                    </a>
                                                                </>
                                                            }
                                                        />
                                                    )}
                                                </Spin>
                                            );
                                        })
                                    }
                                </Form.List>
                                <Divider type="horizontal" style={{ margin: "10px 0" }} />
                            </>
                        )}
                        {modifiableEntries.length > 0 && (
                            <>
                                <div style={{ display: showTermFields ? "block" : "none" }}>
                                    <PluginUpdateTermFields pluginUpdate={pluginUpdate} />
                                </div>
                                {footer}
                            </>
                        )}
                    </Form>
                </>
            )}
        </Spin>
    );
});

export { PluginUpdateForm, PLUGIN_UPDATE_FORM_LAYOUT, PLUGIN_UPDATE_FORM_LAYOUT_MARGIN_BOTTOM };
