<script lang="ts">
  import {Checkbox, InfoTooltip, Input, MenuButton, Textarea} from '../base';
  import {Button, FloatingTrigger, Select} from '../base/index.js';
  import {getCurrentNodeId} from '#components/utils/NodeUtils';
  import {useNodesData, useSvelteFlow} from '@xyflow/svelte';
  import {contentTypes, parameterRefTypes} from '#consts';
  import {useRefOptions} from '../utils/useRefOptions.svelte';
  import {onMount} from 'svelte';
  import type {Parameter, ParameterChangeHandler} from '#types';
  import {deepClone} from '../utils/deepClone';
  import {
    isArrayDataType,
    resolveLoopOutputDataType,
  } from '../../utils/loopScope';

  onMount(() => {
        if (!param.refType) {
            updateRefType({ value: 'ref' }); // 设置数据来源默认值
        }
    });

    const {
        parameter,
        index,
        dataKeyName,
        useChildrenOnly,
        showContentType = false,
        fixedNumberMin,
        fixedNumberMax,
        acceptedContentTypes = [],
        loopOutputAggregation = false,
        onParametersChange
    }: {
        parameter: Parameter,
        index: number,
        dataKeyName: string,
        useChildrenOnly?: boolean,
        showContentType?: boolean,
        fixedNumberMin?: number,
        fixedNumberMax?: number,
        acceptedContentTypes?: string[],
        loopOutputAggregation?: boolean,
        onParametersChange?: ParameterChangeHandler,
    } = $props();


    let currentNodeId = getCurrentNodeId();
    let node = useNodesData(currentNodeId);
    let param = $derived.by(() => {
        return {
            ...parameter,
            ...(node?.current?.data?.[dataKeyName] as Array<Parameter>)[index]
        };
    });

    const { updateNodeData } = useSvelteFlow();

    const updateParams = (patch: Partial<Parameter>) => {
        updateNodeData(currentNodeId, (node) => {
            const previousParameters = deepClone(
                (node.data?.[dataKeyName] as Array<Parameter>) || []
            );
            const nextParameters = deepClone(previousParameters);
            nextParameters[index] = {
                ...nextParameters[index],
                ...patch
            };
            return {
                [dataKeyName]: nextParameters,
                ...onParametersChange?.(
                    previousParameters,
                    nextParameters,
                    node.data
                )
            };
        });
    };

    const updateParam = (key: string, value: any) => {
        updateParams({[key]: value});
    };

    const updateParamByEvent = (name: string, event: Event) => {
        const newValue = (event.target as any).value;
        updateParam(name, newValue);
    };

    let fixedValueHint = $state('');

    const updateFixedValue = (event: Event) => {
        const value = (event.target as HTMLInputElement).value;
        if (fixedNumberMin === undefined && fixedNumberMax === undefined) {
            updateParam('value', value);
            return;
        }
        if (value.trim() === '') {
            fixedValueHint = '';
            updateParam('value', value);
            return;
        }
        const parsed = Number(value);
        if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) {
            fixedValueHint = '请输入整数';
            updateParam('value', value);
            return;
        }
        if (fixedNumberMax !== undefined && parsed > fixedNumberMax) {
            fixedValueHint = `最大支持 ${fixedNumberMax} 次，已调整为 ${fixedNumberMax}`;
            updateParam('value', String(fixedNumberMax));
            return;
        }
        if (fixedNumberMin !== undefined && parsed < fixedNumberMin) {
            fixedValueHint = `最少执行 ${fixedNumberMin} 次`;
            updateParam('value', String(fixedNumberMin));
            return;
        }
        fixedValueHint = '';
        updateParam('value', value);
    };


    const updateRef = (item: any) => {
        const newValue = item.value;
        if (!loopOutputAggregation) {
            updateParam('ref', newValue);
            return;
        }
        const dataType = item.dataType || 'String';
        updateParams({
            ref: newValue,
            dataType,
            flattenAggregation:
                isArrayDataType(dataType)
                    ? Boolean(param.flattenAggregation)
                    : false
        });
    };


    const updateRefType = (item: any) => {
        const newValue = item.value;
        if (!loopOutputAggregation) {
            updateParam('refType', newValue);
            return;
        }
        updateParams({
            refType: newValue,
            flattenAggregation:
                newValue !== 'ref'
                    ? false
                    : Boolean(param.flattenAggregation)
        });
    };

    const updateContentType = (item: any) => {
        const newValue = item.value;
        updateParam('contentType', newValue);
    };


    let triggerObject: any;
    const handleDelete = () => {
        updateNodeData(currentNodeId, (node) => {
            const previousParameters = deepClone(
                (node.data?.[dataKeyName] as Array<Parameter>) || []
            );
            const nextParameters = deepClone(previousParameters);
            nextParameters.splice(index, 1);
            return {
                [dataKeyName]: nextParameters,
                ...onParametersChange?.(
                    previousParameters,
                    nextParameters,
                    node.data
                )
            };
        });
        triggerObject?.hide();
    };
    let selectItems = useRefOptions(
        () => useChildrenOnly === true,
        () => acceptedContentTypes,
        () => param.ref || ''
    );
    let sourceDataType = $derived.by(() => {
        return selectItems.selected?.dataType || param.dataType || 'String';
    });
    let canFlattenAggregation = $derived.by(() => {
        return isArrayDataType(sourceDataType);
    });
    let loopOutputDataType = $derived.by(() => {
        return resolveLoopOutputDataType(
            sourceDataType,
            canFlattenAggregation && Boolean(param.flattenAggregation)
        );
    });
    const updateFlattenAggregation = (event: Event) => {
        const checked = (event.target as HTMLInputElement).checked;
        updateParams({
            dataType: sourceDataType,
            flattenAggregation: canFlattenAggregation && checked
        });
    };
</script>


<div class="input-item">
    <Input style="width: 100%;" value={param.name} placeholder="请输入参数名称"
           disabled={param.nameDisabled === true}
           oninput={(event)=>updateParamByEvent('name', event)} />
</div>
<div class="input-item">
    {#if param.refType === 'fixed'}
        <div class="fixed-value">
            <Input
                type={fixedNumberMin !== undefined || fixedNumberMax !== undefined ? 'number' : 'text'}
                min={fixedNumberMin}
                max={fixedNumberMax}
                step={fixedNumberMin !== undefined || fixedNumberMax !== undefined ? 1 : undefined}
                style="width: 100%;"
                value={param.value}
                placeholder="请输入参数值"
                oninput={updateFixedValue}
            />
            {#if fixedValueHint}
                <span class="input-hint" role="status" aria-live="polite">{fixedValueHint}</span>
            {/if}
        </div>
    {:else if (param.refType !== 'input')}
        <Select items={selectItems.current} style="width: 100%" defaultValue={["ref"]} value={[param.ref]} variant="reference"
                selectedType={loopOutputAggregation ? loopOutputDataType : undefined}
                expandAll
                onSelect={updateRef} />
    {/if}
</div>
<div class="input-item input-actions">
    {#if loopOutputAggregation && param.refType === 'ref' && param.ref && canFlattenAggregation}
        <label class="flatten-aggregation-control">
            <Checkbox
                checked={Boolean(param.flattenAggregation)}
                onchange={updateFlattenAggregation}
            />
            <span>扁平聚合</span>
        </label>
        <InfoTooltip
            label="查看扁平聚合说明"
            text="关闭时按轮次保留数组；开启后按循环顺序合并，只扁平一层。例如 [[A, B], [C]] 会变为 [A, B, C]，轮次分组信息将丢失。"
        />
    {/if}
    <FloatingTrigger placement="bottom" bind:this={triggerObject}>
        <MenuButton />
        {#snippet floating()}
            <div class="input-more-setting">
                <div class="input-more-item">
                    数据来源：
                    <Select items={parameterRefTypes} style="width: 100%" defaultValue={["ref"]}
                            value={param.refType ? [param.refType] : []}
                            onSelect={updateRefType}
                    />
                </div>
                {#if showContentType }
                    <div class="input-more-item">
                        数据内容：
                        <Select items={contentTypes} style="width: 100%" defaultValue={["text"]}
                                value={param.contentType ? [param.contentType] : []}
                                onSelect={updateContentType}
                        />
                    </div>
                {/if}
                <div class="input-more-item">
                    默认值：
                    <Textarea rows={1} style="width: 100%;" onchange={(event)=>{
                        updateParamByEvent('defaultValue', event)
                    }} value={param.defaultValue}  placeholder="请输入参数默认值" />
                </div>
                <div class="input-more-item">
                    参数描述：
                    <Textarea rows={3} style="width: 100%;" onchange={(event)=>{
                        updateParamByEvent('description', event)
                    }} value={param.description}  placeholder="请输入参数描述"/>
                </div>

                <div class="input-more-item">
                    <Button onclick={handleDelete}>删除</Button>
                </div>
            </div>
        {/snippet}
    </FloatingTrigger>
</div>


<style lang="less">

  .input-item {
    display: flex;
    align-items: center;
    width: 100%;
    min-width: 0;
  }

  .input-actions {
    gap: 5px;
    justify-content: flex-end;
    white-space: nowrap;
  }

  .fixed-value {
    display: flex;
    flex-direction: column;
    gap: 3px;
    width: 100%;
    min-width: 0;
  }

  .input-hint {
    color: var(--tf-warning-soft-text);
    font-size: 11px;
    line-height: 1.4;
  }

  .input-more-setting {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 10px;
    background: var(--tf-bg-surface);
    border: 1px solid var(--tf-border-color-strong);
    border-radius: 5px;
    width: 200px;
    box-shadow: var(--tf-shadow-medium);

    .input-more-item {
      display: flex;
      flex-direction: column;
      gap: 3px;
      font-size: 12px;
      color: var(--tf-text-secondary);
    }
  }

  .flatten-aggregation-control {
    display: inline-flex;
    gap: 5px;
    align-items: center;
    color: var(--tf-text-primary);
    cursor: pointer;
    font-size: 11px;
    white-space: nowrap;

    :global(.tf-checkbox:focus-visible) {
      outline: none;
      box-shadow: 0 0 0 2px var(--tf-primary-soft-border);
    }
  }

</style>
