<script setup lang="ts">
import { ref, onMounted, computed } from 'vue';
import { useTaskStore } from '../stores/tasks';
import { useUiStore } from '../stores/ui';
import { useToastStore } from '../stores/toast';
import { api, ApiError } from '../api/client';
import { useSse } from '../composables/useSse';
import { formatGitConflict } from '../lib/gitConflict';
import BranchDropdown from './BranchDropdown.vue';

// connState is the tri-state SSE health ('ok' | 'reconnecting' | 'closed'),
// mirroring the old status-bar.js _updateConnDot. App.vue/useSse thread the
// tasks-stream tri-state through; we fall back to the boolean `connected` when
// only that is supplied.
const props = defineProps<{
  connected: boolean;
  connState?: 'ok' | 'reconnecting' | 'closed';
}>();
defineEmits<{ shortcuts: [] }>();

interface GitWorkspace {
  path: string;
  name?: string;
  branch: string;
  is_git_repo?: boolean;
  ahead_count?: number;
  behind_count?: number;
  has_remote?: boolean;
  main_branch?: string;
  behind_main_count?: number;
}

const store = useTaskStore();
const ui = useUiStore();
const toast = useToastStore();
const workspaces = ref<GitWorkspace[]>([]);
const busy = ref<Record<string, string>>({}); // ws.path -> 'push' | 'sync' | 'rebase'

const dropdownOpen = ref(false);
const dropdownWs = ref<GitWorkspace | null>(null);
const dropdownAnchor = ref<{ top: number; left: number } | null>(null);

function openBranchDropdown(ws: GitWorkspace, e: MouseEvent) {
  e.stopPropagation();
  if (dropdownOpen.value && dropdownWs.value?.path === ws.path) {
    dropdownOpen.value = false;
    return;
  }
  const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
  dropdownAnchor.value = { top: rect.bottom + 4, left: rect.left };
  dropdownWs.value = ws;
  dropdownOpen.value = true;
}

const connState = computed<'ok' | 'reconnecting' | 'closed'>(
  () => props.connState ?? (props.connected ? 'ok' : 'closed'),
);
const connDotClass = computed(() => `status-bar-conn-dot--${connState.value}`);
const connLabel = computed(() =>
  connState.value === 'ok'
    ? 'Connected'
    : connState.value === 'reconnecting'
      ? 'Reconnecting…'
      : 'Disconnected',
);

// Center counts mirror the old _updateCounts: global board totals by status,
// ignoring the active task filter and the archived flag. Binding to
// store.inProgress / store.waiting would shrink these while a search is active.
const inProgressCount = computed(
  () => store.tasks.filter(t => t.status === 'in_progress' || t.status === 'committing').length,
);
const waitingCount = computed(
  () => store.tasks.filter(t => t.status === 'waiting' || t.status === 'failed').length,
);

const workspaceLabel = computed(() => {
  const ws = store.config?.workspaces ?? [];
  if (!ws.length) return '';
  const groups = store.config?.workspace_groups ?? [];
  const matched = groups.find(g =>
    Array.isArray(g.workspaces)
      && g.workspaces.length === ws.length
      && g.workspaces.every((p, i) => p === ws[i]),
  );
  if (matched?.name) return matched.name;
  const first = ws[0].replace(/\/+$/, '').split('/');
  return first[first.length - 1] || ws[0];
});

const renderableWorkspaces = computed(() =>
  workspaces.value.filter(w => (w.is_git_repo ?? true) && w.branch),
);
const isMulti = computed(() => renderableWorkspaces.value.length > 1);

function branchLabel(ws: GitWorkspace): string {
  return isMulti.value && ws.name ? `${ws.name}:${ws.branch}` : ws.branch;
}

async function refreshGitStatus() {
  try {
    // /api/git/status returns a bare array of WorkspaceGitStatus.
    const list = await api<GitWorkspace[]>('GET', '/api/git/status');
    workspaces.value = Array.isArray(list) ? list : [];
  } catch {
    /* git status optional */
  }
}

async function runAction(ws: GitWorkspace, kind: 'push' | 'sync' | 'rebase') {
  if (busy.value[ws.path]) return;
  busy.value[ws.path] = kind;
  try {
    const route = kind === 'push'
      ? '/api/git/push'
      : kind === 'sync'
        ? '/api/git/sync'
        : '/api/git/rebase-on-main';
    await api('POST', route, { workspace: ws.path });
    await refreshGitStatus();
  } catch (e) {
    // A 409 means the mutation is blocked by in-flight tasks; surface the
    // blocking list rather than swallowing it (mirrors ui/js/git.js).
    if (e instanceof ApiError && e.status === 409) {
      const label = kind.charAt(0).toUpperCase() + kind.slice(1);
      toast.push(formatGitConflict(e.body, label), { kind: 'error' });
    }
    /* other errors surface via stale state; status SSE will re-emit */
  } finally {
    delete busy.value[ws.path];
  }
}

// The git stream rides the same tab-leader relay as the tasks stream: only the
// leader tab opens /api/git/stream, followers receive relayed events. This caps
// the origin at one tasks-SSE + one git-SSE total regardless of tab count.
// GitStatusStream sends `data: <bare array>` events with no event name, so the
// default `message` channel (onMessage) is the one we want.
useSse({
  url: '/api/git/stream',
  withCredentials: false,
  onMessage: (ev) => {
    try {
      // Leader receives a raw string; followers receive the already-parsed
      // value relayed verbatim.
      const list = typeof ev.data === 'string' ? JSON.parse(ev.data) : ev.data;
      if (Array.isArray(list)) workspaces.value = list as GitWorkspace[];
    } catch { /* ignore */ }
  },
});

onMounted(() => {
  refreshGitStatus();
});
</script>

<template>
  <footer class="status-bar" role="contentinfo" aria-label="Status bar">
    <div class="status-bar__left">
      <span
        class="status-bar-conn-dot"
        :class="connDotClass"
        :aria-label="connLabel"
      />
      <span class="status-bar-conn-label">{{ connLabel }}</span>
      <span v-if="workspaceLabel" class="status-bar-workspace">{{ workspaceLabel }}</span>
      <span
        v-if="renderableWorkspaces.length"
        class="status-bar-branches"
        aria-label="Workspace branches"
      >
        <span
          v-for="ws in renderableWorkspaces"
          :key="ws.path"
          class="status-bar-branch-group"
        >
          <button
            type="button"
            class="status-bar-branch"
            :title="`${ws.path || ws.name || ''}\nBranch: ${ws.branch}`"
            @click="openBranchDropdown(ws, $event)"
          >
            <span class="status-bar-branch__glyph">⎇</span>
            <span class="status-bar-branch__name">{{ branchLabel(ws) }}</span>
          </button>
          <template v-if="ws.has_remote">
            <span
              v-if="(ws.behind_count ?? 0) > 0"
              class="status-bar-branch__badge status-bar-branch__badge--behind"
              :title="`${ws.behind_count} commits behind upstream`"
            >{{ ws.behind_count }}↓</span>
            <span
              v-if="(ws.ahead_count ?? 0) > 0"
              class="status-bar-branch__badge status-bar-branch__badge--ahead"
              :title="`${ws.ahead_count} commits ahead of upstream`"
            >{{ ws.ahead_count }}↑</span>
            <button
              v-if="(ws.behind_count ?? 0) > 0"
              type="button"
              class="status-bar-branch__action status-bar-branch__action--sync"
              :disabled="!!busy[ws.path]"
              :title="`Pull ${ws.behind_count} commits from upstream`"
              @click="runAction(ws, 'sync')"
            >{{ busy[ws.path] === 'sync' ? '…' : 'Sync' }}</button>
            <button
              v-if="(ws.ahead_count ?? 0) > 0"
              type="button"
              class="status-bar-branch__action status-bar-branch__action--push"
              :disabled="!!busy[ws.path]"
              :title="`Push ${ws.ahead_count} commits to upstream`"
              @click="runAction(ws, 'push')"
            >{{ busy[ws.path] === 'push' ? '…' : 'Push' }}</button>
            <button
              v-if="ws.main_branch && ws.branch !== ws.main_branch"
              type="button"
              class="status-bar-branch__action status-bar-branch__action--rebase"
              :disabled="!!busy[ws.path]"
              :title="`Fetch origin/${ws.main_branch} and rebase current branch on top`"
              @click="runAction(ws, 'rebase')"
            ><template v-if="(ws.behind_main_count ?? 0) > 0">{{ ws.behind_main_count }}↓ </template>{{ busy[ws.path] === 'rebase' ? '…' : `Rebase on ${ws.main_branch}` }}</button>
          </template>
        </span>
      </span>
    </div>
    <div class="status-bar__center">
      <span class="status-bar-count" title="In Progress">
        <svg width="10" height="10" viewBox="0 0 10 10" fill="none" aria-hidden="true">
          <circle cx="5" cy="5" r="4" stroke="currentColor" stroke-width="1.5" />
          <polyline
            points="5,2.5 5,5 7,6.5"
            stroke="currentColor"
            stroke-width="1.2"
            stroke-linecap="round"
          />
        </svg>
        <span id="status-bar-in-progress">{{ inProgressCount }}</span>
      </span>
      <span class="status-bar-count" title="Waiting">
        <svg width="10" height="10" viewBox="0 0 10 10" fill="none" aria-hidden="true">
          <circle cx="5" cy="5" r="4" stroke="currentColor" stroke-width="1.5" />
          <line
            x1="5"
            y1="3"
            x2="5"
            y2="5.5"
            stroke="currentColor"
            stroke-width="1.2"
            stroke-linecap="round"
          />
          <circle cx="5" cy="7" r="0.6" fill="currentColor" />
        </svg>
        <span id="status-bar-waiting">{{ waitingCount }}</span>
      </span>
    </div>
    <div class="status-bar__right">
      <router-link to="/map" class="status-bar-btn" title="Open map">Map</router-link>
      <button
        type="button"
        class="status-bar-btn"
        title="Keyboard shortcuts"
        aria-label="Show keyboard shortcuts"
        @click="$emit('shortcuts')"
      >
        Shortcuts <kbd class="status-bar-kbd">?</kbd>
      </button>
      <button
        type="button"
        class="status-bar-btn"
        title="Toggle terminal panel (Ctrl+`)"
        :aria-expanded="ui.showTerminal"
        aria-controls="status-bar-panel"
        @click="ui.toggleTerminal()"
      >
        Terminal <kbd class="status-bar-kbd">^`</kbd>
      </button>
    </div>
  </footer>
  <BranchDropdown
    v-if="dropdownWs"
    v-model="dropdownOpen"
    :workspace-path="dropdownWs.path"
    :current-branch="dropdownWs.branch"
    :anchor="dropdownAnchor"
    @switched="refreshGitStatus"
  />
</template>
