import React, {
    CSSProperties,
    FC,
    ReactNode,
    useCallback,
    useEffect,
    useMemo,
    useState,
} from "react";
import { Flex, Group } from "@mantine/core";
import AttributeValueInput from "@/app/deals/drawers/DealEditorDrawer/components/AttributeValueInput";
import useDealAttributeValuesActions from "@/components/ui/AttributesEditor/useDealAttributeValuesActions";
import FormFlexRow from "@/components/ui/FormFlexRow/FormFlexRow";
import InlineButton from "@/components/ui/InlineButton/InlineButton";
import {
    DealModuleAttributeSchema,
    DealSchema,
    UpdateDealModuleAttributeSchema,
} from "@/lib/client";

type Props = {
    moduleId: number;
    deal: DealSchema;
    containerStyle?: CSSProperties;
    buttonContainerStyle?: CSSProperties;
    buttonStyle?: CSSProperties;
    attributesInTwoColumns?: boolean;
};

type AttrInfo = {
    value?: any;
    isApplicableToGroup: boolean;
};

const AttributeEditor: FC<Props> = ({
    moduleId,
    deal,
    containerStyle,
    buttonContainerStyle,
    buttonStyle,
    attributesInTwoColumns = true,
}) => {
    const { dealAttributes, updateAttributeValues } =
        useDealAttributeValuesActions({
            moduleId,
            dealId: deal.id,
        });

    const [attributeValuesMap, setAttributeValuesMap] = useState<
        Map<number, AttrInfo | null>
    >(new Map());
    const [attributeErrorsMap, setAttributeErrorsMap] = useState<
        Map<number, string>
    >(new Map());

    useEffect(() => {
        const values = new Map<number, AttrInfo | null>();
        for (const dealAttr of dealAttributes) {
            values.set(dealAttr.attributeId, {
                ...dealAttr,
                value: dealAttr.value,
            });
        }
        setAttributeValuesMap(values);
    }, [dealAttributes]);

    const onSubmit = () => {
        let isErrorFound = false;
        for (const attr of dealAttributes) {
            const value = attributeValuesMap.get(attr.attributeId);
            if (!attr.isNullable && (value === null || value === undefined)) {
                attributeErrorsMap.set(attr.attributeId, "Обязательное поле");
                isErrorFound = true;
            }
        }
        setAttributeErrorsMap(new Map(attributeErrorsMap));
        if (isErrorFound) return;

        const attributeValues: UpdateDealModuleAttributeSchema[] =
            attributeValuesMap
                .entries()
                .map(
                    ([attributeId, info]) =>
                        ({
                            attributeId,
                            ...info,
                        }) as UpdateDealModuleAttributeSchema
                )
                .toArray();

        updateAttributeValues(attributeValues);
    };

    const getAttributeElement = useCallback(
        (attribute: DealModuleAttributeSchema) => (
            <AttributeValueInput
                key={attribute.attributeId}
                attrInfo={attribute}
                value={attributeValuesMap.get(attribute.attributeId)?.value}
                onChange={value => {
                    attributeValuesMap.set(attribute.attributeId, {
                        ...attribute,
                        value,
                    });
                    setAttributeValuesMap(new Map(attributeValuesMap));
                    attributeErrorsMap.delete(attribute.attributeId);
                    setAttributeErrorsMap(new Map(attributeErrorsMap));
                }}
                style={{ flex: 1 }}
                error={attributeErrorsMap.get(attribute.attributeId)}
            />
        ),
        [attributeValuesMap, attributeErrorsMap]
    );

    const attributesRows = useMemo(() => {
        if (!dealAttributes) return [];
        const boolAttributes = dealAttributes.filter(
            a => a.type.type === "bool"
        );
        const otherAttributes = dealAttributes.filter(
            a => a.type.type !== "bool"
        );

        const rows: ReactNode[] = [];

        if (attributesInTwoColumns) {
            for (let i = 0; i < otherAttributes.length; i += 2) {
                const rightIdx = i + 1;

                rows.push(
                    <FormFlexRow key={`row${i}`}>
                        {getAttributeElement(otherAttributes[i])}
                        {rightIdx < otherAttributes.length &&
                            getAttributeElement(otherAttributes[rightIdx])}
                    </FormFlexRow>
                );
            }
        } else {
            for (const attr of otherAttributes) {
                rows.push(getAttributeElement(attr));
            }
        }

        for (const attr of boolAttributes) {
            rows.push(getAttributeElement(attr));
        }

        return rows;
    }, [dealAttributes, getAttributeElement]);

    return (
        <Flex
            direction={"column"}
            gap={"xs"}
            style={containerStyle}>
            {attributesRows}
            <Group style={buttonContainerStyle}>
                <InlineButton
                    style={buttonStyle}
                    onClick={onSubmit}>
                    Сохранить
                </InlineButton>
            </Group>
        </Flex>
    );
};

export default AttributeEditor;
