<template>
  <div class="flex-1 flex flex-col bg-[var(--wraith-bg-primary)] min-h-0 relative">
    <!-- SSH terminal views — v-show keeps xterm alive across tab switches -->
    <div
      v-for="session in sshSessions"
      :key="session.id"
      v-show="session.id === sessionStore.activeSessionId"
      class="absolute inset-0"
    >
      <TerminalView
        :ref="(el) => setTerminalRef(session.id, el)"
        :session-id="session.id"
        :is-active="session.id === sessionStore.activeSessionId"
      />
    </div>

    <!-- Local PTY views — v-show keeps xterm alive across tab switches -->
    <div
      v-for="session in localSessions"
      :key="session.id"
      v-show="session.id === sessionStore.activeSessionId"
      class="absolute inset-0"
    >
      <LocalTerminalView
        :session-id="session.id"
        :is-active="session.id === sessionStore.activeSessionId"
      />
    </div>

    <!-- RDP views — toolbar + canvas, kept alive via v-show -->
    <div
      v-for="session in rdpSessions"
      :key="session.id"
      v-show="session.id === sessionStore.activeSessionId"
      class="absolute inset-0 flex flex-col"
    >
      <RdpToolbar
        :session-id="session.id"
        :keyboard-grabbed="rdpViewRefs[session.id]?.keyboardGrabbed.value ?? false"
        :clipboard-sync="rdpViewRefs[session.id]?.clipboardSync.value ?? false"
        @toggle-keyboard="rdpViewRefs[session.id]?.toggleKeyboardGrab()"
        @toggle-clipboard="rdpViewRefs[session.id]?.toggleClipboardSync()"
        @ctrl-alt-del="sendCtrlAltDel(session.id)"
        @fullscreen="toggleFullscreen(rdpViewRefs[session.id]?.canvasWrapper)"
        @send-clipboard="(text) => sendClipboardToSession(session.id, text)"
      />
      <RdpView
        :ref="(el) => setRdpRef(session.id, el)"
        :session-id="session.id"
        :is-active="session.id === sessionStore.activeSessionId"
      />
    </div>

    <!-- No session placeholder -->
    <div
      v-if="!sessionStore.activeSession"
      class="flex-1 flex items-center justify-center"
    >
      <div class="text-center">
        <p class="text-[var(--wraith-text-muted)] text-sm">
          No active session
        </p>
        <p class="text-[var(--wraith-text-muted)] text-xs mt-1">
          Double-click a connection to start a session
        </p>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, ref } from "vue";
import { invoke } from "@tauri-apps/api/core";
import { useSessionStore } from "@/stores/session.store";
import TerminalView from "@/components/terminal/TerminalView.vue";
import LocalTerminalView from "@/components/terminal/LocalTerminalView.vue";
import RdpView from "@/components/rdp/RdpView.vue";
import RdpToolbar from "@/components/rdp/RdpToolbar.vue";
import { ScancodeMap } from "@/composables/useRdp";

/** Map from session ID → TerminalView instance ref (for search access). */
const terminalViewRefs: Record<string, { openSearch: () => void } | null> = {};

function setTerminalRef(sessionId: string, el: unknown): void {
  if (el) {
    terminalViewRefs[sessionId] = el as { openSearch: () => void };
  } else {
    delete terminalViewRefs[sessionId];
  }
}

const sessionStore = useSessionStore();

const sshSessions = computed(() =>
  sessionStore.sessions.filter((s) => s.protocol === "ssh"),
);

const localSessions = computed(() =>
  sessionStore.sessions.filter((s) => s.protocol === "local"),
);

const rdpSessions = computed(() =>
  sessionStore.sessions.filter((s) => s.protocol === "rdp"),
);

/**
 * Map from session ID → exposed RdpView instance ref.
 * The ref callback pattern (`:ref="(el) => ..."`) gives us per-session access
 * to each RdpView's composable state without a single shared ref.
 */
const rdpViewRefs = ref<
  Record<
    string,
    {
      keyboardGrabbed: { value: boolean };
      clipboardSync: { value: boolean };
      toggleKeyboardGrab: () => void;
      toggleClipboardSync: () => void;
      canvasWrapper: { value: HTMLElement | null };
    } | null
  >
>({});

function setRdpRef(
  sessionId: string,
  el: unknown,
): void {
  if (el) {
    rdpViewRefs.value[sessionId] = el as typeof rdpViewRefs.value[string];
  } else {
    delete rdpViewRefs.value[sessionId];
  }
}

/**
 * Send Ctrl+Alt+Del to a remote RDP session by injecting the three
 * scancodes in the correct order: Ctrl down, Alt down, Del down, then up.
 */
async function sendCtrlAltDel(sessionId: string): Promise<void> {
  const ctrl = ScancodeMap["ControlLeft"];
  const alt = ScancodeMap["AltLeft"];
  const del = ScancodeMap["Delete"];

  const sequence: Array<[number, boolean]> = [
    [ctrl, true],
    [alt, true],
    [del, true],
    [del, false],
    [alt, false],
    [ctrl, false],
  ];

  for (const [scancode, pressed] of sequence) {
    try {
      await invoke("rdp_send_key", { sessionId, scancode, pressed });
    } catch (err) {
      console.warn("[SessionContainer] Ctrl+Alt+Del key send failed:", err);
    }
  }
}

/**
 * Forward clipboard text from the host to the remote RDP session.
 */
function sendClipboardToSession(sessionId: string, text: string): void {
  invoke("rdp_send_clipboard", { sessionId, text }).catch((err: unknown) => {
    console.warn("[SessionContainer] sendClipboard failed:", err);
  });
}

/**
 * Toggle fullscreen on the canvas wrapper element.
 */
function toggleFullscreen(wrapperRef: { value: HTMLElement | null } | undefined): void {
  const wrapper = wrapperRef?.value;
  if (!wrapper) return;

  if (document.fullscreenElement) {
    document.exitFullscreen();
  } else {
    wrapper.requestFullscreen();
  }
}

/**
 * Open the inline search bar on the currently active SSH terminal.
 * No-op if the active session is RDP (no terminal to search).
 */
function openActiveSearch(): void {
  const activeId = sessionStore.activeSessionId;
  if (!activeId) return;
  const termRef = terminalViewRefs[activeId];
  termRef?.openSearch();
}

defineExpose({ openActiveSearch });
</script>
