export type AttributeGroupOption = {
    id: number;
    name: string;
};

export type AttributeDefinition = {
    id: number;
    name: string;
    type: string;
    unit: string | null;
    is_required: boolean;
    group: AttributeGroupOption | null;
};

type GroupedAttributes = {
    key: string;
    label: string;
    attributes: AttributeDefinition[];
};

type ProductAttributeSelectorProps = {
    attributeDefinitions: AttributeDefinition[];
    attributeValues: Record<string, string>;
    errors: Record<string, string | undefined>;
    selectedAttributeGroupKeys: string[];
    selectedAttributeIds: number[];
    onToggleGroup: (
        groupKey: string,
        attributeIds: number[],
        checked: boolean,
    ) => void;
    onToggleAttribute: (attributeId: number, checked: boolean) => void;
    onValueChange: (attributeId: number, value: string) => void;
};

export function ProductAttributeSelector({
    attributeDefinitions,
    attributeValues,
    errors,
    selectedAttributeGroupKeys,
    selectedAttributeIds,
    onToggleGroup,
    onToggleAttribute,
    onValueChange,
}: ProductAttributeSelectorProps) {
    const groupedAttributes = groupAttributes(attributeDefinitions);

    if (groupedAttributes.length === 0) {
        return null;
    }

    const selectedGroupKeySet = new Set(selectedAttributeGroupKeys);
    const selectedAttributeIdSet = new Set(selectedAttributeIds);
    const selectedGroups = groupedAttributes.filter((group) =>
        selectedGroupKeySet.has(group.key),
    );

    return (
        <div className="space-y-4 rounded-2xl border border-slate-200 bg-slate-50/70 p-4 dark:border-[#3c2b68] dark:bg-[#2a1d50]/35">
            <div>
                <h2 className="text-base font-semibold text-[#0a1530] dark:text-[#efe8ff]">
                    Technical Attributes
                </h2>
                <p className="text-sm text-slate-600 dark:text-[#c7bde8]">
                    Select the attribute groups and attributes used by this
                    product.
                </p>
            </div>

            <div className="grid gap-2 sm:grid-cols-2 lg:grid-cols-3">
                {groupedAttributes.map((group) => {
                    const checked = selectedGroupKeySet.has(group.key);

                    return (
                        <label
                            key={group.key}
                            className="flex items-center gap-2 rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm text-[#0a1530] dark:border-[#3c2b68] dark:bg-[#211740] dark:text-[#e5dcff]"
                        >
                            <input
                                type="checkbox"
                                checked={checked}
                                onChange={(event) =>
                                    onToggleGroup(
                                        group.key,
                                        group.attributes.map(
                                            (attribute) => attribute.id,
                                        ),
                                        event.target.checked,
                                    )
                                }
                                className="h-4 w-4 rounded border-slate-300 text-[#0b7285] focus:ring-[#0b7285] dark:border-[#4a3a78]"
                            />
                            <span>{group.label}</span>
                        </label>
                    );
                })}
            </div>

            {selectedGroups.length > 0 ? (
                <div className="space-y-4">
                    {selectedGroups.map((group) => (
                        <div key={group.key} className="space-y-3">
                            <p className="text-sm font-semibold text-[#0a1530] dark:text-[#efe8ff]">
                                {group.label}
                            </p>
                            <div className="grid gap-4 md:grid-cols-2">
                                {group.attributes.map((attribute) => {
                                    const checked = selectedAttributeIdSet.has(
                                        attribute.id,
                                    );
                                    const value =
                                        attributeValues[String(attribute.id)] ||
                                        '';
                                    const error =
                                        errors[
                                            `attribute_values.${attribute.id}`
                                        ];

                                    return (
                                        <div
                                            key={attribute.id}
                                            className="space-y-2"
                                        >
                                            <label className="flex items-center gap-2 text-sm font-medium text-[#0a1530] dark:text-[#e5dcff]">
                                                <input
                                                    type="checkbox"
                                                    checked={checked}
                                                    onChange={(event) =>
                                                        onToggleAttribute(
                                                            attribute.id,
                                                            event.target
                                                                .checked,
                                                        )
                                                    }
                                                    className="h-4 w-4 rounded border-slate-300 text-[#0b7285] focus:ring-[#0b7285] dark:border-[#4a3a78]"
                                                />
                                                <span>
                                                    {attribute.name}
                                                    {attribute.unit
                                                        ? ` (${attribute.unit})`
                                                        : ''}
                                                    {attribute.is_required
                                                        ? ' *'
                                                        : ''}
                                                </span>
                                            </label>
                                            {checked ? (
                                                <AttributeInput
                                                    attribute={attribute}
                                                    value={value}
                                                    onChange={(next) =>
                                                        onValueChange(
                                                            attribute.id,
                                                            next,
                                                        )
                                                    }
                                                />
                                            ) : null}
                                            {error ? (
                                                <p className="text-xs text-rose-600">
                                                    {error}
                                                </p>
                                            ) : null}
                                        </div>
                                    );
                                })}
                            </div>
                        </div>
                    ))}
                </div>
            ) : (
                <p className="text-sm text-slate-500 dark:text-[#bcaee6]">
                    No technical attributes selected.
                </p>
            )}
        </div>
    );
}

function AttributeInput({
    attribute,
    value,
    onChange,
}: {
    attribute: AttributeDefinition;
    value: string;
    onChange: (value: string) => void;
}) {
    if (attribute.type === 'boolean') {
        return (
            <select
                value={value}
                onChange={(event) => onChange(event.target.value)}
                className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]"
            >
                <option value="">Not set</option>
                <option value="1">Yes</option>
                <option value="0">No</option>
            </select>
        );
    }

    if (attribute.type === 'number') {
        return (
            <input
                type="number"
                step="any"
                value={value}
                onChange={(event) => onChange(event.target.value)}
                className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]"
            />
        );
    }

    return (
        <input
            value={value}
            onChange={(event) => onChange(event.target.value)}
            className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]"
        />
    );
}

export function groupAttributes(
    attributes: AttributeDefinition[],
): GroupedAttributes[] {
    const groups = new Map<string, GroupedAttributes>();

    attributes.forEach((attribute) => {
        const key = attributeGroupKey(attribute);
        const label = attribute.group ? attribute.group.name : 'General';

        if (!groups.has(key)) {
            groups.set(key, {
                key,
                label,
                attributes: [],
            });
        }

        groups.get(key)?.attributes.push(attribute);
    });

    return Array.from(groups.values());
}

export function buildInitialAttributeValues(
    attributes: AttributeDefinition[],
    existingValues: Record<string, string>,
): Record<string, string> {
    return attributes.reduce<Record<string, string>>((carry, attribute) => {
        carry[String(attribute.id)] =
            existingValues[String(attribute.id)] || '';

        return carry;
    }, {});
}

export function selectedAttributeIdsFromValues(
    attributes: AttributeDefinition[],
    existingValues: Record<string, string>,
): number[] {
    return attributes
        .filter((attribute) => {
            const value = existingValues[String(attribute.id)];

            return value !== undefined && String(value).trim() !== '';
        })
        .map((attribute) => attribute.id);
}

export function selectedAttributeGroupKeysFromAttributeIds(
    attributes: AttributeDefinition[],
    attributeIds: number[],
): string[] {
    const selectedIds = new Set(attributeIds);
    const groupKeys = attributes
        .filter((attribute) => selectedIds.has(attribute.id))
        .map((attribute) => attributeGroupKey(attribute));

    return Array.from(new Set(groupKeys));
}

export function buildSubmittedAttributeValues(
    values: Record<string, string>,
    selectedAttributeIds: number[],
): Record<string, string> {
    const submittedValues: Record<string, string> = {};

    selectedAttributeIds.forEach((attributeId) => {
        submittedValues[String(attributeId)] =
            values[String(attributeId)] || '';
    });

    return submittedValues;
}

export function buildRemovedAttributeIds(
    selectedAttributeIds: number[],
    initiallySelectedAttributeIds: number[],
): number[] {
    const selectedIds = new Set(selectedAttributeIds);

    return initiallySelectedAttributeIds.filter(
        (attributeId) => !selectedIds.has(attributeId),
    );
}

function attributeGroupKey(attribute: AttributeDefinition): string {
    return attribute.group ? `group-${attribute.group.id}` : 'general';
}
