<template>
  <q-page>
    <q-layout container class="absolute-full shadow-2 rounded-borders">
      <div class="q-pa-sm q-gutter-sm  ">
        <q-drawer side="left" :overlay="true" bordered v-model="drawerLeft" :show-if-above="false" elevated>
          <div class="flex-center absolute-full" style="padding:15px">
            <q-scroll-area class="fit" :horizontal-thumb-style="{ opacity: '0' }">
              <EventTree />
            </q-scroll-area>
          </div>

          <div class="flex-center fixed-bottom bg-grey-3 q-pa-md row ">
            <q-btn color="secondary" glossy label="デプロイ" @click="onDeploy" icon="sync" :loading="deployLoading" />
            <q-space></q-space>
            <q-btn-dropdown color="primary" label="保存" icon="save" :loading="saveLoading" >
              <q-list>
                <q-item clickable v-close-popup @click="onSaveVersion">
                  <q-item-section avatar >
                    <q-icon name="bookmark_border"></q-icon>
                  </q-item-section>
                  <q-item-section>
                    <q-item-label>保存して新バージョン</q-item-label>
                  </q-item-section>
                </q-item>

                <q-item clickable v-close-popup @click="onSaveFlow">
                  <q-item-section avatar >
                    <q-icon name="save" color="primary"></q-icon>
                  </q-item-section>
                  <q-item-section>
                    <q-item-label>選択中フローの保存</q-item-label>
                  </q-item-section>
                </q-item>

                <q-item clickable v-close-popup @click="onSaveAllFlow">
                  <q-item-section avatar>
                    <q-icon name="collections_bookmark" color="accent"></q-icon>
                  </q-item-section>
                  <q-item-section>
                    <q-item-label>一括保存</q-item-label>
                  </q-item-section>
                </q-item>
              </q-list>
            </q-btn-dropdown>
          </div>
        </q-drawer>
      </div>
      <q-btn flat dense round
              :icon="drawerLeft?'keyboard_double_arrow_left':'keyboard_double_arrow_right'"
              :style="{'left': fixedLeftPosition}"
              @click="drawerLeft=!drawerLeft" class="expand" />
      <q-breadcrumbs v-if="store.appInfo" class="fixed q-pl-md"
              :style="{'left': fixedLeftPosition}">
        <q-breadcrumbs-el icon="widgets" label="アプリ" to="/app" />
        <q-breadcrumbs-el>
          <template v-slot>
            <a class="full-width" :href="store.appInfo ? `${authStore.currentDomain.kintoneUrl}/k/${store.appInfo?.appId}` : ''" target="_blank" title="Kiontoneへ">
              {{ store.appInfo?.name }}
              <q-icon
                class="q-ma-xs"
                name="open_in_new"
                color="grey-9"
              />
            </a>
          </template>
        </q-breadcrumbs-el>
      </q-breadcrumbs>
      <div class="q-pa-md q-gutter-sm" :style="{minWidth: minPanelWidth}">
        <div class="flowchart" v-if="store.currentFlow" :style="[drawerLeft?{paddingLeft:'300px'}:{}]">
          <node-item v-if="rootNode!==undefined" :key="rootNode.id" :isSelected="rootNode === store.activeNode"
            :actionNode="rootNode" @addNode="addNode" @nodeSelected="onNodeSelected" @nodeEdit="onNodeEdit"
            @deleteNode="onDeleteNode" @deleteAllNextNodes="onDeleteAllNextNodes" @copyFlow="onCopyFlow"></node-item>
        </div>
      </div>
      <PropertyPanel :actionNode="store.activeNode" v-model:drawerRight="drawerRight" @save-action-props="onSaveActionProps"></PropertyPanel>
    </q-layout>
    <ShowDialog v-model:visible="showAddAction" name="アクション" @close="closeDg" min-width="500px" min-height="500px">
      <template v-slot:toolbar>
        <q-input  dense debounce="200" v-model="filter" placeholder="検索" clearable>
          <template v-slot:before>
            <q-icon name="search" />
          </template>
        </q-input>
      </template>
      <action-select ref="appDg" name="model" :filter="filter"  type="single" @clearFilter="onClearFilter" ></action-select>
    </ShowDialog>
    <!-- save version dialog -->
    <ShowDialog v-model:visible="saveVersionAction" name="保存して新バージョン" @close="closeSaveVersionDg" :ok-btn-auto-close="false" min-width="500px">
      <version-input ref="versionInputRef" v-model="versionSubmit" />
    </ShowDialog>
    <q-inner-loading
      :showing="initLoading"
      color="primary"
      label="読み込み中..."
    />
  </q-page>
</template>

<script setup lang="ts">
import { ref, reactive, computed, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { IActionNode, ActionNode, IActionFlow, ActionFlow, RootAction, IActionProperty, AppInfo } from 'src/types/ActionTypes';
import { IAppDisplay, IManagedApp, IVersionSubmit } from 'src/types/AppTypes';
import { storeToRefs } from 'pinia';
import { useFlowEditorStore } from 'stores/flowEditor';
import { useAuthStore } from 'stores/useAuthStore';
import { useAppStore } from 'stores/useAppStore';
import { api } from 'boot/axios';

import NodeItem from 'src/components/main/NodeItem.vue';
import ShowDialog from 'components/ShowDialog.vue';
import ActionSelect from 'components/ActionSelect.vue';
import PropertyPanel from 'components/right/PropertyPanel.vue';
import EventTree from 'components/left/EventTree.vue';
import VersionInput from 'components/dialog/VersionInput.vue';
import { FlowCtrl } from '../control/flowctrl';
import { useQuasar } from 'quasar';

const deployLoading = ref(false);
const saveLoading = ref(false);
const initLoading = ref(true);
const drawerLeft = ref(false);
const versionSubmit = ref<IVersionSubmit>({} as IVersionSubmit);
const $q = useQuasar();
const store = useFlowEditorStore();
const authStore = useAuthStore();
const appStore = useAppStore();
const route = useRoute()

const appDg = ref();
const prevNodeIfo = ref({
  prevNode: {} as IActionNode,
  inputPoint: ''
});
// const refFlow = ref<ActionFlow|null>(null);
const showAddAction = ref(false);
const saveVersionAction = ref(false);
const versionInputRef = ref();
const drawerRight = ref(false);
const filter=ref('');
const model = ref('');

const rootNode = computed(()=>{
  return store.currentFlow?.getRoot();
});
const minPanelWidth=computed(()=>{
  const root = store.currentFlow?.getRoot();
  if(store.currentFlow && root){
    return store.currentFlow?.getColumns(root) * 300 + 'px';
  }else{
    return '300px';
  }
});
const fixedLeftPosition = computed(()=>{
  return drawerLeft.value?'300px':'0px';
});

const addNode = (node: IActionNode, inputPoint: string) => {
  if (drawerRight.value) {
    drawerRight.value = false;
  }
  showAddAction.value = true;
  prevNodeIfo.value.prevNode = node;
  prevNodeIfo.value.inputPoint = inputPoint;
}

const onNodeSelected = (node: IActionNode) => {
  //右パネルが開いている場合、自動閉じる
  if (drawerRight.value && store.activeNode?.id !== node.id) {
    drawerRight.value = false;
  }
  store.setActiveNode(node);
}

const onNodeEdit = (node: IActionNode) => {
  store.setActiveNode(node);
  drawerRight.value = true;
}

const onDeleteNode = (node: IActionNode) => {
  if (!store.currentFlow) return;
  //右パネルが開いている場合、自動閉じる
  if (drawerRight.value && store.activeNode?.id === node.id) {
    drawerRight.value = false;
  }
  store.currentFlow?.removeNode(node);
}

const onDeleteAllNextNodes = (node: IActionNode) => {
  if (!store.currentFlow) return;
  //右パネルが開いている場合、自動閉じる
  if (drawerRight.value) {
    drawerRight.value = false;
  }
  store.currentFlow?.removeAllNext(node.id);
}
const closeDg = (val: any) => {
  console.log('Dialog closed->', val);
  if (val == 'OK' && appDg?.value?.selected?.length > 0) {
    const data = appDg.value.selected[0];
    const actionProps = JSON.parse(data.property);
    const outputPoint = JSON.parse(data.outputPoints);
    const action = new ActionNode(data.name, data.desc, '', outputPoint, actionProps);
    store.currentFlow?.addNode(action, prevNodeIfo.value.prevNode, prevNodeIfo.value.inputPoint);
  }
}
/*
 *フローのデータをコピーする
 */
const onCopyFlow = () => {
  if (navigator.clipboard) {
    const jsonData =JSON.stringify(store.currentFlow) ;
    navigator.clipboard.writeText(jsonData).then(() => {
      console.log('Text successfully copied to clipboard');
    },
      (err) => {
        console.error('Error in copying text: ', err);
      });
  } else {
    console.log('Clipboard API not available');
  }
};
/**
 * デプロイ
 */
const onDeploy = async () => {
  if (store.appInfo === undefined || store.flows?.length === 0) {
    $q.notify({
      type: 'negative',
      caption: 'エラー',
      message: '設定されたフローがありません。'
    });
    return;
  }

  deployLoading.value = true;
  try {
    const { data }: {data: {code: string, groups: {code: string}[]}} = await api.get('api/v1/defaultgroup');
    if (data.code === 'CB_WA01') {
      $q.notify({
        type: 'negative',
        caption: 'エラー',
        message: 'ユーザーのパスワード認証に失敗しました。'
      });
      deployLoading.value = false;
      return;
    } else if (!data.groups || !data.groups.some((group: {code: string}) => group.code === 'Administrators')){
      $q.notify({
        type: 'negative',
        caption: 'エラー',
        message: 'この操作には管理者権限が必要です。'
      });
      deployLoading.value = false;
      return;
    }
  } catch (e) {
    $q.notify({
      type: 'negative',
      caption: 'エラー',
      message: 'サーバーに接続できませんでした。'
    });
    deployLoading.value = false;
    return;
  }

  try {
    await store.deploy();
    deployLoading.value = false;
    $q.notify({
      type: 'positive',
      caption: '通知',
      message: 'デプロイを成功しました。'
    });
  } catch (error) {
    console.error(error);
    deployLoading.value = false;
    $q.notify({
      type: 'negative',
      caption: 'エラー',
      message: 'デプロイが失敗しました。'
    })
  }
  return;
}

const onSaveActionProps=(props:IActionProperty[])=>{
  if(store.activeNode){
      store.activeNode.actionProps=props;
      $q.notify({
        type: 'positive',
        caption: '通知',
        message: `${store.activeNode?.subTitle}の属性を設定しました。（保存はされていません）`
      });
  }
};

const onSaveVersion = async () => {
  if (!store.appInfo) return;
  versionSubmit.value = { appId: store.appInfo.appId }
  saveVersionAction.value = true;
}

const closeSaveVersionDg = async (val: 'OK'|'CANCEL') => {
  saveVersionAction.value = true;
  if (val == 'OK') {
    if (versionInputRef?.value?.isValid()) {
      saveVersionAction.value = false;
      await onSaveAllFlow();
      await appStore.createVersion(versionSubmit.value);
    } else {
      saveVersionAction.value = true;
    }
  } else {
    saveVersionAction.value = false;
  }
}

const onSaveFlow = async () => {
  const targetFlow = store.selectedFlow;
  if (targetFlow === undefined) {
    $q.notify({
      type: 'negative',
      caption: 'エラー',
      message: '選択中のフローがありません。'
    });
    return;
  }
  try {
    saveLoading.value = true;
    await store.saveFlow(targetFlow);
    saveLoading.value = false;
    $q.notify({
      type: 'positive',
      caption: '通知',
      message: `${targetFlow.getRoot()?.subTitle}のフロー設定を保存しました。`
    });
  } catch (error) {
    console.error(error);
    saveLoading.value = false;
    $q.notify({
      type: 'negative',
      caption: 'エラー',
      message: `${targetFlow.getRoot()?.subTitle}のフローの設定の保存が失敗しました。`
    })
  }
}
/**
 * すべてフローの設定を保存する
 */
const onSaveAllFlow= async ()=>{
  try{
    const targetFlows = store.eventTree.findAllFlows();
    if (!targetFlows || targetFlows.length === 0 ) {
      $q.notify({
        type: 'negative',
        caption: 'エラー',
        message: '設定されたフローがありません。'
      });
      return;
    }
    saveLoading.value = true;
    for(const flow of targetFlows ){
      const isNew = flow.id === '';
      if(isNew && flow.actionNodes.length===1){
        continue;
      }
      await store.saveFlow(flow);
    }
    $q.notify({
        type: 'positive',
        caption: '通知',
        message: 'すべてのフロー設定を保存しました。'
      });
    saveLoading.value = false;
  }catch (error) {
    console.error(error);
    saveLoading.value = false;
    $q.notify({
      type: 'negative',
      caption: 'エラー',
      message: 'フローの設定の保存が失敗しました。'
    });
  }
}

const fetchData = async () => {
  initLoading.value = true;
  if (store.appInfo === undefined && route?.params?.id !== undefined) {
    // only for page refreshed
    const app = await fetchAppById(route.params.id as string);
    store.setApp(app);
  };
  await store.loadFlow();
  initLoading.value = false
  drawerLeft.value = true;
}

const fetchAppById = async(id: string) => {
  let result = await api.get('api/apps');
  const app = result.data?.data?.find((item: IManagedApp) => item.appid === id ) as IManagedApp;
  if (app) {
    return convertManagedAppToAppInfo(app);
  }

  result = await api.get(`api/v1/app?app=${id}`);
  const kApp = result?.data as IAppDisplay | KErrorMsg;
  if (isErrorMsg(kApp)) {
    $q.notify({
      type: 'negative',
      caption: 'エラー',
      message: kApp.message,
    });
  }
  return kApp;
}

type KErrorMsg = {
  message: string;
}

const isErrorMsg = (e: IAppDisplay | KErrorMsg): e is KErrorMsg => {
  return 'message' in e;
};

const convertManagedAppToAppInfo = (app: IManagedApp): AppInfo => {
  return {
    appId: app.appid,
    name: app.appname
  }
};

const onClearFilter=()=>{
  filter.value='';
}

onMounted(async () => {
  authStore.setLeftMenu(false);
  await fetchData();
});
</script>

<style lang="scss">
.flowchart {
  padding-top: 10px;
}

.flow-toolbar {
  opacity: 50%;
}

.event-tree .q-drawer {
  top: 50px;
  z-index: 999;
}
.expand{
  position: fixed;
  left: 0px;
  top: 50%;
  z-index: 9999;
}
</style>
