<template>
    <div class="q-my-md" v-bind="$attrs">
        <q-field :label="displayName" labelColor="primary" stack-label
          v-model="mappingProps"
          :rules="rulesExp"
          ref="fieldRef"
        >
            <template v-slot:control>
                <q-card flat class="full-width">
                    <q-card-actions vertical>
                        <q-btn color="grey-3" text-color="black" :disable="btnDisable"
                            @click="() => { dgIsShow = true }">クリックで設定</q-btn>
                    </q-card-actions>
                    <q-card-section class="text-caption">
                        <div v-if="mappingObjectsInputDisplay && mappingObjectsInputDisplay.length > 0">
                            <div v-for="(item) in mappingObjectsInputDisplay" :key="item">{{ item }}</div>
                        </div>
                        <div v-else>{{ placeholder }}</div>
                    </q-card-section>
                </q-card>
            </template>
        </q-field>
        <show-dialog v-model:visible="dgIsShow" name="データマッピング" @close="closeDg" min-width="55vw" min-height="60vh">
            <div class="">
                <div class="row q-col-gutter-x-xs flex-center">
                    <div class="col-5">
                        <div class="q-mx-xs">ソース</div>
                    </div>
                    <!-- <div class="col-1">
                    </div> -->
                    <div class="col-5">
                        <div class="row justify-between q-mr-md">
                            <div class="">{{ sourceApp?.name }}</div>
                            <q-btn outline color="primary" size="xs" label="最新のフィールドを取得する"
                                @click="() => updateFields(sourceAppId!)" />
                        </div>
                    </div>
                    <div class="col-1 q-pl-sm">
                        キー
                    </div>
                </div>
                <q-virtual-scroll style="max-height: 60vh;" :items="mappingProps.data" separator v-slot="{ item, index }">
                    <!-- <div class="q-my-sm" v-for="(item, index) in mappingProps" :key="item.id"> -->
                    <div class="row q-pa-sm q-col-gutter-x-md flex-center">
                        <div class="col-5">
                            <ConditionObject :config="config" v-model="item.from" :disabled="item.disabled"
                                :label="item.disabled ? '「Lookup」によってロックされる' : undefined" />
                        </div>
                        <!-- <div class="col-1">
                        </div> -->
                        <div class="col-5">
                            <q-field v-model="item.vName" type="text" outlined dense :disable="item.disabled" >
                                <!-- <template v-slot:append>
                                    <q-icon name="search" class="cursor-pointer"
                                        @click="() => { mappingProps[index].to.isDialogVisible = true }" />
                                </template> -->
                                <template v-slot:control>
                                     <div class="self-center full-width no-outline" tabindex="0"
                                        v-if="item.to.app?.name && item.to.fields?.length > 0 && item.to.fields[0].label">
                                        {{ `${item.to.fields[0].label}` }}
                                        <span class="text-red" v-if="item.to.fields[0].required">*</span>
                                        <q-tooltip class="bg-yellow-2 text-black shadow-4" >
                                            <div>アプリ : {{ item.to.app.name }}</div>
                                            <div>フィールドのコード : {{ item.to.fields[0].code }}</div>
                                            <div>フィールドのタイプ : {{ item.to.fields[0].type }}</div>
                                            <div v-if="item.to.fields[0].required">必須項目</div>
                                            <!-- <div>フィールド : {{ item.to.fields[0] }}</div>
                                            <div>フィールド : {{ item.isKey }}</div> -->
                                        </q-tooltip>
                                    </div>
                                </template>
                            </q-field>
                        </div>
                        <div class="col-1">
                            <q-checkbox size="sm" v-model="item.isKey" :disable="item.disabled" />
                            <!-- <q-btn flat round dense icon="delete" size="sm" @click="() => deleteMappingObject(index)" /> -->
                        </div>
                    </div>

                    <show-dialog v-model:visible="mappingProps.data[index].to.isDialogVisible" name="フィールド一覧"
                        @close="closeToDg" ref="fieldDlg">
                        <FieldSelect v-if="onlySourceSelect" ref="fieldDlg" name="フィールド" :appId="sourceAppId" not_page
                            :selectedFields="mappingProps.data[index].to.fields"
                            :updateSelects="(fields) => { mappingProps.data[index].to.fields = fields; mappingProps.data[index].to.app = sourceApp }">
                        </FieldSelect>
                        <AppFieldSelectBox v-else v-model:selectedField="mappingProps.data[index].to" />
                    </show-dialog>
                    <!-- </div> -->
                </q-virtual-scroll>

                <div class="q-mt-lg q-ml-md row ">
                    <q-checkbox size="sm" v-model="mappingProps.createWithNull" label="キーが存在しない場合は新規に作成され、存在する場合はデータが更新されます。" />
                </div>
            </div>
        </show-dialog>
    </div>
</template>

<script lang="ts">
import { v4 as uuidv4 } from 'uuid';
import { computed, defineComponent, watch, isRef, reactive, ref, watchEffect } from 'vue';
import ConditionObject from '../ConditionEditor/ConditionObject.vue';
import ShowDialog from '../ShowDialog.vue';
import AppFieldSelectBox from '../AppFieldSelectBox.vue';
import FieldSelect from '../FieldSelect.vue';
import { IApp, IField } from './AppFieldSelect.vue';
import { api } from 'boot/axios';

type ContextProps = {
    props?: {
        name: string;
        modelValue?: {
            app: {
                id: string;
                name: string;
            }
        }
    }
};

interface IMappingSetting {
    data: IMappingValueType[];
    createWithNull: boolean;
}

interface IMappingValueType {
    id: string;
    from: { sharedText?: string };
    to: {
        app?: IApp,
        fields: IField[],
        isDialogVisible: boolean;
    };
    isKey: boolean;
    disabled: boolean;
}

const blackListLabelName = ['レコード番号', '作業者', '更新者', '更新日時', '作成日時', '作成者']

export default defineComponent({
    name: 'DataMapping',
    inheritAttrs: false,
    components: {
        ShowDialog,
        ConditionObject,
        AppFieldSelectBox,
        FieldSelect
    },
    props: {
        context: {
            type: Array<ContextProps>,
            default: '',
        },
        displayName: {
            type: String,
            default: '',
        },
        name: {
            type: String,
            default: '',
        },
        modelValue: {
            type: Object as () => IMappingSetting,
        },
        placeholder: {
            type: String,
            default: '',
        },
        onlySourceSelect: {
            type: Boolean,
            default: false
        },
        fieldTypes:{
          type:Array,
          default:()=>[]
        },
        //例：[val=>!!val ||'入力してください']
        rules: {
          type: String,
          default: undefined
        },
        required: {
          type: Boolean,
          default: false
        },
        requiredMessage: {
          type: String,
          default: ''
        }
    },
    setup(props, { emit }) {
        const fieldRef=ref();
        const source = props.context.find(element => element?.props?.name === 'sources')

        const sourceApp = computed(() => source?.props?.modelValue?.app);

        const sourceAppId = computed(() => sourceApp.value?.id);

         //ルール設定
        const checkMapping = (val:IMappingSetting)=>{
          if(!val || !val.data){
            return false;
          }
          console.log(val);
          const mappingDatas = val.data.filter(item=>item.from?.sharedText && item.to.fields?.length > 0);
          return mappingDatas.length>0;
        }
        const customExp = props.rules === undefined ? [] : eval(props.rules);
        const errmsg = props.requiredMessage?props.requiredMessage:`${props.displayName}を選択してください。`;
        const requiredExp = props.required ? [((val: any) => checkMapping(val) || errmsg)] : [];
        const rulesExp = [...requiredExp, ...customExp];

        // const mappingProps = ref(props.modelValue?.data ?? []);

        // const createWithNull = ref(props.modelValue?.createWithNull ?? false);

        const mappingProps = reactive<IMappingSetting>({
          data:props.modelValue?.data ?? [],
          createWithNull:props.modelValue?.createWithNull ?? false
        });

        const closeDg = () => {
          fieldRef.value.validate();
          emit('update:modelValue',mappingProps);
        }

        const closeToDg = () => {
          emit('update:modelValue',mappingProps);
        }

        // 外部ソースコンポーネントの appid をリッスンし、変更されたときに現在のコンポーネントを更新します
        watch(() => sourceAppId.value, async (newId,) => {
            if (!newId) return;
            updateFields(newId)
        })

        const updateFields = async (sourceAppId: string) => {
            const ktAppFields = await api.get('api/v1/appfields', {
                params: {
                    app: sourceAppId
                }
            }).then(res => {
                return Object.values(res.data.properties)
                    // kintoneのデフォルトの非表示フィールドフィルタリング
                    .filter(f => !blackListLabelName.find(label => f.label === label))
                    .map(f => ({ name: f.label, objectType: 'field', ...f }))
                    .map(f => {
                        // 更新前の値を求める
                        const beforeData = mappingProps.data.find(m => m.to.fields[0].code === f.code)
                        return {
                            id: uuidv4(),
                            from: beforeData?.from ?? {}, // 以前のデータを入力します
                            to: {
                                app: sourceApp.value,
                                fields: [f],
                                isDialogVisible: false
                            },
                            isKey: beforeData?.isKey ?? false, // 以前のデータを入力します
                            disabled: false
                        }
                    })
            })

            // 「ルックアップ」によってロックされているフィールドを検索する
            const lookupFixedField = ktAppFields
                .filter(field => field.to.fields[0].lookup !== undefined)
                .flatMap(field => field.to.fields[0].lookup.fieldMappings.map((m) => m.field))

            // 「ルックアップ」でロックされたビューコンポーネントを非対話型に設定します
            if (lookupFixedField.length > 0) {
                ktAppFields.filter(f => lookupFixedField.includes(f.to.fields[0].code)).forEach(f => f.disabled = true)
            }

            mappingProps.data = ktAppFields
        }

        const mappingObjectsInputDisplay = computed(() =>
            (mappingProps.data && Array.isArray(mappingProps.data)) ?
                mappingProps.data
                    .filter(item => item.from?.sharedText && item.to.fields?.length > 0)
                    .map(item => {
                        return `field(${item.to.app?.id},${item.to.fields[0].label}) = ${item.from.sharedText} `;
                    })
                : []
        );

        const btnDisable = computed(() => props.onlySourceSelect ? !(source?.props?.modelValue?.app?.id) : false);

        watchEffect(() => {
            emit('update:modelValue', mappingProps);
        });

        return {
            uuidv4,
            dgIsShow: ref(false),
            fieldRef,
            closeDg,
            toDgIsShow: ref(false),
            closeToDg,
            mappingProps,
            updateFields,
            // addMappingObject: () => mappingProps.push(defaultMappingProp()),
            // deleteMappingObject,
            mappingObjectsInputDisplay,
            sourceApp,
            sourceAppId,
            btnDisable,
            rulesExp,
            checkMapping,
            config: {
                canInput: false,
                buttonsConfig: [
                    { label: 'フィールド', color: 'primary', type: 'FieldAdd' },
                    { label: '変数', color: 'green', type: 'VariableAdd', editable: false },
                ]
            }
        };
    },
});

</script>
<style lang="scss"></style>
