<script setup lang="ts">
import {
  Ref,
  computed,
  h,
  nextTick,
  onActivated,
  onMounted,
  onUnmounted,
  ref,
} from "vue";
import {
  Device,
  adbDevices,
  pushServerFile,
  forwardServerPort,
  startScrcpyServer,
  getScreenSize,
} from "../invoke";
import {
  NH4,
  NInputNumber,
  NButton,
  NDataTable,
  NDropdown,
  NEmpty,
  NTooltip,
  NFlex,
  NIcon,
  NSpin,
  DataTableColumns,
  DropdownOption,
  useDialog,
} from "naive-ui";
import { CloseCircle, InformationCircle } from "@vicons/ionicons5";
import { Refresh } from "@vicons/ionicons5";
import { UnlistenFn, listen } from "@tauri-apps/api/event";
import { shutdown } from "../frontcommand/scrcpyMaskCmd";
import { useGlobalStore } from "../store/global";

const dialog = useDialog();
const store = useGlobalStore();

const port = ref(27183);

//#region listener
const deviceWaitForMetadataTask: ((deviceName: string) => void)[] = [];

let unlisten: UnlistenFn | undefined;
onMounted(async () => {
  unlisten = await listen("device-reply", (event) => {
    try {
      let payload = JSON.parse(event.payload as string);
      switch (payload.type) {
        case "MetaData":
          let task = deviceWaitForMetadataTask.shift();
          task?.(payload.deviceName);
          break;
        case "ClipboardChanged":
          console.log("剪切板变动", payload.clipboard);
          break;
        case "ClipboardSetAck":
          console.log("剪切板设置成功", payload.sequence);
          break;
        default:
          console.log("Unknown reply", payload);
          break;
      }
    } catch (e) {
      console.error(e);
    }
  });
});

onActivated(async () => {
  await refreshDevices();
});

onUnmounted(() => {
  if (unlisten !== undefined) unlisten();
});
//#endregion

//#region table
const devices: Ref<Device[]> = ref([]);
const availableDevice = computed(() => {
  return devices.value.filter((d) => {
    return store.controledDevice?.device.id !== d.id;
  });
});
const tableCols: DataTableColumns = [
  {
    title: "ID",
    key: "id",
  },
  {
    title: "Status",
    key: "status",
  },
];

// record last operated row index
let rowIndex = -1;

// table row contextmenu and click event handler
const tableRowProps = (_: any, index: number) => {
  return {
    onContextmenu: (e: MouseEvent) => {
      e.preventDefault();
      showMenu.value = false;
      rowIndex = index;
      nextTick().then(() => {
        showMenu.value = true;
        menuX.value = e.clientX;
        menuY.value = e.clientY;
      });
    },
    onclick: (e: MouseEvent) => {
      e.preventDefault();
      showMenu.value = false;
      rowIndex = index;
      nextTick().then(() => {
        showMenu.value = true;
        menuX.value = e.clientX;
        menuY.value = e.clientY;
      });
    },
  };
};
//#endregion

//#region controled device

async function shutdownSC() {
  dialog.warning({
    title: "Warning",
    content: "确定关闭Scrcpy控制服务?",
    positiveText: "确定",
    negativeText: "取消",
    onPositiveClick: async () => {
      await shutdown();
      store.controledDevice = null;
    },
  });
}
//#endregion

//#region menu
const menuX = ref(0);
const menuY = ref(0);
const showMenu = ref(false);
const menuOptions: DropdownOption[] = [
  {
    label: () => h("span", "控制此设备"),
    key: "control",
  },
];

function onMenuClickoutside() {
  showMenu.value = false;
}

async function onMenuSelect(key: string) {
  showMenu.value = false;
  store.showLoading();
  switch (key) {
    case "control":
      if (!port.value) {
        port.value = 27183;
      }
      let device = devices.value[rowIndex];

      let scid = (
        "00000000" + Math.floor(Math.random() * 100000).toString(16)
      ).slice(-8);

      let screenSize = await getScreenSize(device.id);

      await pushServerFile(device.id);
      await forwardServerPort(device.id, scid, port.value);
      await startScrcpyServer(device.id, scid, `127.0.0.1:${port.value}`);

      // add cb for metadata
      deviceWaitForMetadataTask.push((deviceName: string) => {
        store.controledDevice = {
          scid,
          deviceName,
          device,
          screenSize,
        };
        nextTick(() => {
          store.hideLoading();
        });
      });
      break;
  }
}
//#endregion

async function refreshDevices() {
  store.showLoading();
  devices.value = await adbDevices();
  store.hideLoading();
}

const screenSizeInfo = computed(() => {
  if (store.controledDevice) {
    return `${store.controledDevice.screenSize[0]} x ${store.controledDevice.screenSize[1]}`;
  }
  return "";
});
</script>

<template>
  <div class="device">
    <NSpin :show="store.showLoadingRef">
      <NH4 prefix="bar">本地端口</NH4>
      <NInputNumber
        v-model:value="port"
        :show-button="false"
        :min="16384"
        :max="49151"
        style="max-width: 300px"
      />
      <NH4 prefix="bar">受控设备</NH4>
      <div class="controled-device-list">
        <NEmpty
          size="small"
          description="No Controled Device"
          v-if="!store.controledDevice"
        />
        <div class="controled-device" v-if="store.controledDevice">
          <div>
            {{ store.controledDevice.deviceName }} ({{
              store.controledDevice.device.id
            }})
          </div>
          <div class="device-op">
            <NTooltip trigger="hover">
              <template #trigger>
                <NButton quaternary circle type="info">
                  <template #icon>
                    <NIcon><InformationCircle /></NIcon>
                  </template>
                </NButton>
              </template>
              scid: {{ store.controledDevice.scid }} <br />status:
              {{ store.controledDevice.device.status }} <br />screen:
              {{ screenSizeInfo }}
            </NTooltip>
            <NButton quaternary circle type="error" @click="shutdownSC()">
              <template #icon>
                <NIcon><CloseCircle /></NIcon>
              </template>
            </NButton>
          </div>
        </div>
      </div>
      <NFlex justify="space-between" align="center">
        <NH4 prefix="bar">可用设备</NH4>
        <NButton
          tertiary
          circle
          type="primary"
          @click="refreshDevices"
          style="margin-right: 20px"
        >
          <template #icon>
            <NIcon><Refresh /></NIcon>
          </template>
        </NButton>
      </NFlex>
      <NDataTable
        max-height="120"
        :columns="tableCols"
        :data="availableDevice"
        :row-props="tableRowProps"
        :pagination="false"
        :bordered="false"
      />
      <NDropdown
        placement="bottom-start"
        trigger="manual"
        :x="menuX"
        :y="menuY"
        :options="menuOptions"
        :show="showMenu"
        :on-clickoutside="onMenuClickoutside"
        @select="onMenuSelect"
      />
    </NSpin>
  </div>
</template>

<style scoped lang="scss">
.device {
  color: var(--light-color);
  background-color: var(--bg-color);
  padding: 0 25px;
}

.n-h4 {
  margin-top: 20px;
}

.controled-device-list {
  .controled-device {
    padding: 10px 20px;
    background-color: var(--content-bg-color);
    border: 2px solid var(--content-hl-color);
    border-bottom: none;
    border-radius: 5px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    transition: background-color 0.3s;
    &:last-child {
      border-bottom: 2px solid var(--content-hl-color);
    }
    &:hover {
      background-color: var(--content-hl-color);
    }

    .device-op {
      display: flex;
      align-items: center;
      gap: 10px;
    }
  }
}
</style>
