import { UploadOutlined } from "@ant-design/icons";
import { App, Form, Input, Radio, Select, Spin, Switch, Upload } from "antd";
import { observer } from "mobx-react";
import { useCallback, useEffect, useState } from "react";

import { ImportFormResultMessage } from "./resultMessages.js";
import { useStores } from "../../../store/stores.js";
import { __ } from "../../../utils/i18n.js";
import { request } from "../../../utils/request.js";
import { locationRestImportPost } from "../../../wp-api/import.post.js";

import type {
    ParamsRouteImportPost,
    RequestRouteImportPost,
    ResponseRouteImportPost,
} from "../../../wp-api/import.post.js";
import type { ComponentProps, FC } from "react";

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

const ImportForm: FC = observer(() => {
    const { message } = App.useApp();
    const { cookieStore, optionStore } = useStores();
    const { groups, busy } = cookieStore;
    const [form] = Form.useForm();
    const [isBusy, setBusy] = useState(false);
    const [result, setResult] = useState<ResponseRouteImportPost>(undefined);
    const initialValues: Partial<ParamsRouteImportPost> = {
        json: "",
        cookieStatus: "keep",
        cookieSkipExisting: true,
        blockerStatus: "keep",
        blockerSkipExisting: true,
        tcfVendorConfigurationStatus: "keep",
    };

    // Initially load all available cookie groups
    useEffect(() => {
        cookieStore.fetchGroups();
    }, []);

    // Request export data from REST API
    const handleFinish: ComponentProps<typeof Form>["onFinish"] = useCallback(async (values) => {
        setBusy(true);
        try {
            setResult(
                await request<RequestRouteImportPost, ParamsRouteImportPost, ResponseRouteImportPost>({
                    location: locationRestImportPost,
                    request: {
                        cookieGroup: 0,
                        cookieStatus: "keep",
                        cookieSkipExisting: true,
                        blockerStatus: "keep",
                        blockerSkipExisting: true,
                        tcfVendorConfigurationStatus: "keep",
                        ...(values as RequestRouteImportPost),
                    },
                }),
            );
            optionStore.fetchCurrentRevision();
            optionStore.fetchSettings();
            optionStore.fetchBannerLinks();
            message.success(__("Successfully imported!"));
        } catch (e) {
            message.error(e.responseJSON.message);
        } finally {
            setBusy(false);
        }
    }, []);

    // Upload is currently not a real upload, instead the content is read and put into the textarea
    const handleUploadFile: ComponentProps<typeof Upload>["beforeUpload"] = useCallback(
        (file) => {
            const reader = new FileReader();
            reader.readAsText(file, "UTF-8");
            reader.onload = (evt) =>
                form.setFieldsValue({
                    json: evt.target.result,
                });
            reader.onerror = () =>
                form.setFieldsValue({
                    json: __("File could not be read."),
                });
            return false;
        },
        [form],
    );

    // Check if a given JSON is valid and has a first level key
    const hasValidJson = useCallback((json: string, keyToCheck?: string) => {
        try {
            const obj = JSON.parse(json);
            return keyToCheck ? !!obj[keyToCheck] : true;
        } catch (e) {
            return false;
        }
    }, []);

    return (
        <Spin spinning={isBusy || busy}>
            <Form name="import" form={form} {...LAYOUT} initialValues={initialValues} onFinish={handleFinish} labelWrap>
                <Form.Item label={__("Content to import")} required>
                    <Form.Item
                        name="json"
                        rules={[{ required: true, message: __("Please provide a value!") }]}
                        extra={__(
                            "You can get the settings as JSON file or text if you export the settings in this or another WordPress installation.",
                        )}
                    >
                        <Input.TextArea rows={5} />
                    </Form.Item>
                    <p className="description">{__("or select a file to upload:")}</p>
                    <Upload accept="application/json" showUploadList={false} beforeUpload={handleUploadFile}>
                        <a className="button">
                            <UploadOutlined /> {__("Select File")}
                        </a>
                    </Upload>
                </Form.Item>
                <Form.Item noStyle shouldUpdate={(prevValues, nextValues) => prevValues.json !== nextValues.json}>
                    {({ getFieldValue }) => {
                        return (
                            hasValidJson(getFieldValue("json") as string, "cookies") && (
                                <Form.Item label={__("Fallback service group")} required>
                                    <Form.Item
                                        name="cookieGroup"
                                        noStyle
                                        rules={[{ required: true, message: __("Please provide a group!") }]}
                                    >
                                        <Select style={{ width: "70%" }}>
                                            {groups.sortedGroups.map(({ data: { id, name } }) => (
                                                <Select.Option key={id} value={id}>
                                                    {name}
                                                </Select.Option>
                                            ))}
                                        </Select>
                                    </Form.Item>
                                    <p className="description">
                                        {__(
                                            "Select an alternative group to assign the service to if an imported service cannot be assigned to its original group.",
                                        )}
                                    </p>
                                </Form.Item>
                            )
                        );
                    }}
                </Form.Item>
                <Form.Item noStyle shouldUpdate={(prevValues, nextValues) => prevValues.json !== nextValues.json}>
                    {({ getFieldValue }) => {
                        return (
                            hasValidJson(getFieldValue("json") as string, "cookies") && (
                                <>
                                    <Form.Item>
                                        <span>
                                            <Form.Item name="cookieSkipExisting" valuePropName="checked" noStyle>
                                                <Switch />
                                            </Form.Item>
                                            <span>&nbsp;&nbsp;{__("Skip already existing services")}</span>
                                        </span>
                                    </Form.Item>
                                    <Form.Item
                                        label={__("Set service status")}
                                        name="cookieStatus"
                                        rules={[{ required: true, message: __("Please choose a status!") }]}
                                    >
                                        <Radio.Group>
                                            <Radio.Button value="keep">{__("Keep")}</Radio.Button>
                                            <Radio.Button value="publish">{__("Enabled")}</Radio.Button>
                                            <Radio.Button value="private">{__("Disabled")}</Radio.Button>
                                            <Radio.Button value="draft">{__("Draft")}</Radio.Button>
                                        </Radio.Group>
                                    </Form.Item>
                                </>
                            )
                        );
                    }}
                </Form.Item>
                <Form.Item noStyle shouldUpdate={(prevValues, nextValues) => prevValues.json !== nextValues.json}>
                    {({ getFieldValue }) => {
                        return (
                            hasValidJson(getFieldValue("json") as string, "blocker") && (
                                <>
                                    <Form.Item>
                                        <span>
                                            <Form.Item name="blockerSkipExisting" valuePropName="checked" noStyle>
                                                <Switch />
                                            </Form.Item>
                                            <span>&nbsp;&nbsp;{__("Skip already existing content blocker")}</span>
                                        </span>
                                    </Form.Item>
                                    <Form.Item
                                        label={__("Set content blocker status")}
                                        name="blockerStatus"
                                        rules={[{ required: true, message: __("Please choose a status!") }]}
                                    >
                                        <Radio.Group>
                                            <Radio.Button value="keep">{__("Keep")}</Radio.Button>
                                            <Radio.Button value="publish">{__("Enabled")}</Radio.Button>
                                            <Radio.Button value="private">{__("Disabled")}</Radio.Button>
                                            <Radio.Button value="draft">{__("Draft")}</Radio.Button>
                                        </Radio.Group>
                                    </Form.Item>
                                </>
                            )
                        );
                    }}
                </Form.Item>
                <Form.Item noStyle shouldUpdate={(prevValues, nextValues) => prevValues.json !== nextValues.json}>
                    {({ getFieldValue }) => {
                        return (
                            hasValidJson(getFieldValue("json") as string, "tcfVendorConfigurations") && (
                                <Form.Item
                                    label={__("Set TCF Vendor configuration status")}
                                    name="tcfVendorConfigurationStatus"
                                    rules={[{ required: true, message: __("Please choose a status!") }]}
                                >
                                    <Radio.Group>
                                        <Radio.Button value="keep">{__("Keep")}</Radio.Button>
                                        <Radio.Button value="publish">{__("Enabled")}</Radio.Button>
                                        <Radio.Button value="private">{__("Disabled")}</Radio.Button>
                                        <Radio.Button value="draft">{__("Draft")}</Radio.Button>
                                    </Radio.Group>
                                </Form.Item>
                            )
                        );
                    }}
                </Form.Item>
                <Form.Item>
                    <input
                        type="submit"
                        className="button button-primary"
                        style={{ marginTop: 10 }}
                        value={__("Import")}
                    />
                </Form.Item>
                <Form.Item style={{ display: result?.messages?.length ? "block" : "none" }}>
                    <ImportFormResultMessage result={result} />
                </Form.Item>
            </Form>
        </Spin>
    );
});

export { ImportForm };
