<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue'

interface FileNode {
  name: string
  path: string
  type: 'file' | 'dir'
  children?: FileNode[]
  expanded?: boolean
}

interface RepoInfo {
  name: string
  description: string
  default_branch: string
  stars_count: number
  forks_count: number
  owner: { login: string }
}

// Connection settings
const giteaUrl = ref('https://gitea.nucleoriofrio.com')
const username = ref('')
const password = ref('')
const owner = ref('nucleo000')
const repo = ref('agent-ui')
const connected = ref(false)
const connecting = ref(false)
const connectionError = ref<string | null>(null)

// Repository data
const repoInfo = ref<RepoInfo | null>(null)
const fileTree = ref<FileNode[]>([])
const currentBranch = ref('main')
const branches = ref<string[]>([])

// File viewer
const selectedFile = ref<string | null>(null)
const fileContent = ref<string>('')
const fileLoading = ref(false)
const fileName = ref('')

// UI state
const showSettings = ref(true)
const searchQuery = ref('')

// Load saved settings from localStorage
onMounted(() => {
  const saved = localStorage.getItem('gitea_settings')
  if (saved) {
    try {
      const settings = JSON.parse(saved)
      giteaUrl.value = settings.giteaUrl || giteaUrl.value
      username.value = settings.username || ''
      owner.value = settings.owner || ''
      repo.value = settings.repo || ''
      // Don't load password from localStorage for security
    } catch (e) {
      console.error('Error loading saved settings')
    }
  }
})

// Save settings (except password)
function saveSettings() {
  localStorage.setItem('gitea_settings', JSON.stringify({
    giteaUrl: giteaUrl.value,
    username: username.value,
    owner: owner.value,
    repo: repo.value
  }))
}

async function connect() {
  if (!username.value || !password.value || !owner.value || !repo.value) {
    connectionError.value = 'All fields are required'
    return
  }

  connecting.value = true
  connectionError.value = null

  try {
    // Test connection and get repo info
    const res = await fetch('/api/gitea/repo', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        giteaUrl: giteaUrl.value,
        username: username.value,
        password: password.value,
        owner: owner.value,
        repo: repo.value
      })
    })

    if (!res.ok) {
      const err = await res.json()
      throw new Error(err.error || 'Connection failed')
    }

    const data = await res.json()
    repoInfo.value = data.repo
    branches.value = data.branches || ['main']
    currentBranch.value = data.repo.default_branch || 'main'

    // Save settings and load file tree
    saveSettings()
    connected.value = true
    showSettings.value = false

    await loadFileTree()
  } catch (e: any) {
    connectionError.value = e.message
  } finally {
    connecting.value = false
  }
}

async function loadFileTree(path: string = '') {
  try {
    const res = await fetch('/api/gitea/tree', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        giteaUrl: giteaUrl.value,
        username: username.value,
        password: password.value,
        owner: owner.value,
        repo: repo.value,
        branch: currentBranch.value,
        path
      })
    })

    if (!res.ok) throw new Error('Failed to load file tree')

    const data = await res.json()

    if (path === '') {
      fileTree.value = data.tree
    } else {
      // Update nested path
      updateTreeNode(fileTree.value, path, data.tree)
    }
  } catch (e: any) {
    console.error('Error loading tree:', e)
  }
}

function updateTreeNode(nodes: FileNode[], path: string, children: FileNode[]) {
  for (const node of nodes) {
    if (node.path === path) {
      node.children = children
      node.expanded = true
      return true
    }
    if (node.children && updateTreeNode(node.children, path, children)) {
      return true
    }
  }
  return false
}

async function toggleFolder(node: FileNode) {
  if (node.type !== 'dir') return

  if (node.expanded) {
    node.expanded = false
  } else {
    if (!node.children || node.children.length === 0) {
      await loadFileTree(node.path)
    }
    node.expanded = true
  }
}

async function selectFile(node: FileNode) {
  if (node.type !== 'file') return

  selectedFile.value = node.path
  fileName.value = node.name
  fileLoading.value = true
  fileContent.value = ''

  try {
    const res = await fetch('/api/gitea/file', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        giteaUrl: giteaUrl.value,
        username: username.value,
        password: password.value,
        owner: owner.value,
        repo: repo.value,
        branch: currentBranch.value,
        path: node.path
      })
    })

    if (!res.ok) throw new Error('Failed to load file')

    const data = await res.json()
    fileContent.value = data.content
  } catch (e: any) {
    fileContent.value = `Error loading file: ${e.message}`
  } finally {
    fileLoading.value = false
  }
}

function disconnect() {
  connected.value = false
  repoInfo.value = null
  fileTree.value = []
  selectedFile.value = null
  fileContent.value = ''
  password.value = ''
  showSettings.value = true
}

function getFileExtension(filename: string): string {
  return filename.split('.').pop()?.toLowerCase() || ''
}

function getLanguageClass(filename: string): string {
  const ext = getFileExtension(filename)
  const langMap: Record<string, string> = {
    ts: 'typescript',
    tsx: 'typescript',
    js: 'javascript',
    jsx: 'javascript',
    vue: 'vue',
    html: 'html',
    css: 'css',
    scss: 'scss',
    json: 'json',
    md: 'markdown',
    py: 'python',
    go: 'go',
    rs: 'rust',
    sql: 'sql',
    sh: 'bash',
    yml: 'yaml',
    yaml: 'yaml'
  }
  return langMap[ext] || 'plaintext'
}

function getFileIcon(node: FileNode): string {
  if (node.type === 'dir') return ''
  const ext = getFileExtension(node.name)
  const icons: Record<string, string> = {
    ts: 'TS',
    tsx: 'TX',
    js: 'JS',
    vue: 'V',
    json: '{}',
    md: 'M',
    css: '#',
    html: '<>',
    py: 'Py',
    go: 'Go'
  }
  return icons[ext] || ''
}

const filteredTree = computed(() => {
  if (!searchQuery.value) return fileTree.value

  function filterNodes(nodes: FileNode[]): FileNode[] {
    return nodes.filter(node => {
      if (node.name.toLowerCase().includes(searchQuery.value.toLowerCase())) {
        return true
      }
      if (node.children) {
        const filtered = filterNodes(node.children)
        if (filtered.length > 0) {
          node.children = filtered
          node.expanded = true
          return true
        }
      }
      return false
    })
  }

  return filterNodes(JSON.parse(JSON.stringify(fileTree.value)))
})

async function changeBranch() {
  fileTree.value = []
  selectedFile.value = null
  fileContent.value = ''
  await loadFileTree()
}

const lineNumbers = computed(() => {
  if (!fileContent.value) return []
  return fileContent.value.split('\n').map((_, i) => i + 1)
})
</script>

<template>
  <div class="source-page">
    <!-- Sidebar -->
    <aside class="sidebar" :class="{ collapsed: !showSettings && connected }">
      <!-- Settings Panel -->
      <div v-if="showSettings || !connected" class="settings-panel">
        <div class="settings-header">
          <h2>Gitea Connection</h2>
        </div>

        <div class="settings-form">
          <div class="form-group">
            <label>Gitea URL</label>
            <input
              v-model="giteaUrl"
              type="text"
              placeholder="https://gitea.example.com"
            />
          </div>

          <div class="form-group">
            <label>Username</label>
            <input
              v-model="username"
              type="text"
              placeholder="your-username"
              autocomplete="username"
            />
          </div>

          <div class="form-group">
            <label>Password / Token</label>
            <input
              v-model="password"
              type="password"
              placeholder="password or access token"
              autocomplete="current-password"
            />
          </div>

          <div class="form-row">
            <div class="form-group">
              <label>Owner</label>
              <input
                v-model="owner"
                type="text"
                placeholder="owner"
              />
            </div>
            <div class="form-group">
              <label>Repository</label>
              <input
                v-model="repo"
                type="text"
                placeholder="repo-name"
              />
            </div>
          </div>

          <div v-if="connectionError" class="error-message">
            {{ connectionError }}
          </div>

          <button
            class="btn-primary"
            @click="connect"
            :disabled="connecting"
          >
            {{ connecting ? 'Connecting...' : 'Connect' }}
          </button>
        </div>
      </div>

      <!-- File Tree -->
      <div v-else class="file-explorer">
        <div class="explorer-header">
          <div class="repo-info">
            <span class="repo-name">{{ owner }}/{{ repo }}</span>
            <select v-model="currentBranch" @change="changeBranch" class="branch-select">
              <option v-for="branch in branches" :key="branch" :value="branch">
                {{ branch }}
              </option>
            </select>
          </div>
          <button class="btn-icon" @click="showSettings = true" title="Settings">
            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
              <circle cx="12" cy="12" r="3"/>
              <path d="M12 1v4M12 19v4M4.22 4.22l2.83 2.83M16.95 16.95l2.83 2.83M1 12h4M19 12h4M4.22 19.78l2.83-2.83M16.95 7.05l2.83-2.83"/>
            </svg>
          </button>
        </div>

        <div class="search-box">
          <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <circle cx="11" cy="11" r="8"/>
            <line x1="21" y1="21" x2="16.65" y2="16.65"/>
          </svg>
          <input
            v-model="searchQuery"
            type="text"
            placeholder="Search files..."
          />
        </div>

        <div class="tree-container">
          <template v-for="node in filteredTree" :key="node.path">
            <div
              class="tree-node"
              :class="{
                folder: node.type === 'dir',
                file: node.type === 'file',
                selected: selectedFile === node.path
              }"
              @click="node.type === 'dir' ? toggleFolder(node) : selectFile(node)"
            >
              <span v-if="node.type === 'dir'" class="node-icon folder-icon">
                <svg v-if="node.expanded" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                  <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
                  <line x1="9" y1="14" x2="15" y2="14"/>
                </svg>
                <svg v-else xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                  <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
                </svg>
              </span>
              <span v-else class="node-icon file-icon">{{ getFileIcon(node) }}</span>
              <span class="node-name">{{ node.name }}</span>
            </div>

            <!-- Nested children -->
            <div v-if="node.type === 'dir' && node.expanded && node.children" class="tree-children">
              <template v-for="child in node.children" :key="child.path">
                <div
                  class="tree-node"
                  :class="{
                    folder: child.type === 'dir',
                    file: child.type === 'file',
                    selected: selectedFile === child.path
                  }"
                  @click="child.type === 'dir' ? toggleFolder(child) : selectFile(child)"
                >
                  <span v-if="child.type === 'dir'" class="node-icon folder-icon">
                    <svg v-if="child.expanded" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                      <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
                      <line x1="9" y1="14" x2="15" y2="14"/>
                    </svg>
                    <svg v-else xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                      <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1 2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
                    </svg>
                  </span>
                  <span v-else class="node-icon file-icon">{{ getFileIcon(child) }}</span>
                  <span class="node-name">{{ child.name }}</span>
                </div>

                <!-- Level 2 children -->
                <div v-if="child.type === 'dir' && child.expanded && child.children" class="tree-children">
                  <div
                    v-for="grandchild in child.children"
                    :key="grandchild.path"
                    class="tree-node"
                    :class="{
                      folder: grandchild.type === 'dir',
                      file: grandchild.type === 'file',
                      selected: selectedFile === grandchild.path
                    }"
                    @click="grandchild.type === 'dir' ? toggleFolder(grandchild) : selectFile(grandchild)"
                  >
                    <span v-if="grandchild.type === 'dir'" class="node-icon folder-icon">
                      <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                        <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
                      </svg>
                    </span>
                    <span v-else class="node-icon file-icon">{{ getFileIcon(grandchild) }}</span>
                    <span class="node-name">{{ grandchild.name }}</span>
                  </div>
                </div>
              </template>
            </div>
          </template>
        </div>

        <div class="explorer-footer">
          <button class="btn-disconnect" @click="disconnect">
            Disconnect
          </button>
        </div>
      </div>
    </aside>

    <!-- Code Viewer -->
    <main class="code-viewer">
      <div v-if="!connected" class="placeholder">
        <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
          <polyline points="16 18 22 12 16 6"/>
          <polyline points="8 6 2 12 8 18"/>
        </svg>
        <h3>Source Code Viewer</h3>
        <p>Connect to Gitea to browse your repository</p>
      </div>

      <div v-else-if="!selectedFile" class="placeholder">
        <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
          <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
          <polyline points="14 2 14 8 20 8"/>
        </svg>
        <p>Select a file to view its contents</p>
      </div>

      <div v-else class="file-view">
        <div class="file-header">
          <div class="file-path">
            <span class="path-segment" v-for="(segment, idx) in selectedFile.split('/')" :key="idx">
              {{ segment }}
              <span v-if="idx < selectedFile.split('/').length - 1" class="separator">/</span>
            </span>
          </div>
          <div class="file-actions">
            <span class="language-badge">{{ getLanguageClass(fileName) }}</span>
          </div>
        </div>

        <div class="code-container">
          <div v-if="fileLoading" class="loading">Loading file...</div>
          <div v-else class="code-content">
            <div class="line-numbers">
              <span v-for="num in lineNumbers" :key="num">{{ num }}</span>
            </div>
            <pre class="code-text"><code>{{ fileContent }}</code></pre>
          </div>
        </div>
      </div>
    </main>
  </div>
</template>

<style scoped>
.source-page {
  display: flex;
  flex: 1;
  overflow: hidden;
  background: var(--bg-primary);
}

/* Sidebar */
.sidebar {
  width: 300px;
  background: var(--bg-secondary);
  border-right: 1px solid var(--border-color);
  display: flex;
  flex-direction: column;
  transition: width 0.2s ease;
}

.sidebar.collapsed {
  width: 280px;
}

/* Settings Panel */
.settings-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}

.settings-header {
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--border-color);
}

.settings-header h2 {
  margin: 0;
  font-size: 1rem;
  color: var(--text-primary);
}

.settings-form {
  padding: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.form-group {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

.form-group label {
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--text-secondary);
}

.form-group input {
  padding: 0.625rem 0.875rem;
  background: var(--bg-primary);
  border: 1px solid var(--border-color);
  border-radius: 6px;
  color: var(--text-primary);
  font-size: 0.875rem;
}

.form-group input:focus {
  outline: none;
  border-color: var(--accent);
}

.form-row {
  display: flex;
  gap: 0.75rem;
}

.form-row .form-group {
  flex: 1;
}

.error-message {
  padding: 0.625rem;
  background: var(--error-bg);
  color: var(--error);
  border-radius: 6px;
  font-size: 0.8rem;
}

.btn-primary {
  padding: 0.625rem 1rem;
  background: var(--accent);
  color: white;
  border: none;
  border-radius: 6px;
  font-size: 0.875rem;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s;
}

.btn-primary:hover:not(:disabled) {
  background: var(--accent-hover);
}

.btn-primary:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* File Explorer */
.file-explorer {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.explorer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border-color);
}

.repo-info {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

.repo-name {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-primary);
}

.branch-select {
  padding: 0.25rem 0.5rem;
  background: var(--bg-primary);
  border: 1px solid var(--border-color);
  border-radius: 4px;
  color: var(--text-secondary);
  font-size: 0.75rem;
  cursor: pointer;
}

.btn-icon {
  padding: 0.375rem;
  background: transparent;
  border: none;
  border-radius: 6px;
  color: var(--text-secondary);
  cursor: pointer;
}

.btn-icon:hover {
  background: var(--bg-hover);
  color: var(--accent);
}

.search-box {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  border-bottom: 1px solid var(--border-color);
}

.search-box svg {
  color: var(--text-muted);
  flex-shrink: 0;
}

.search-box input {
  flex: 1;
  padding: 0.375rem;
  background: transparent;
  border: none;
  color: var(--text-primary);
  font-size: 0.8rem;
}

.search-box input:focus {
  outline: none;
}

.tree-container {
  flex: 1;
  overflow-y: auto;
  padding: 0.5rem;
}

.tree-node {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.375rem 0.625rem;
  border-radius: 4px;
  cursor: pointer;
  transition: background 0.1s;
}

.tree-node:hover {
  background: var(--bg-hover);
}

.tree-node.selected {
  background: var(--accent-muted);
  color: var(--accent);
}

.tree-children {
  padding-left: 1rem;
}

.node-icon {
  width: 18px;
  height: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.folder-icon {
  color: var(--accent);
}

.file-icon {
  font-size: 0.65rem;
  font-weight: 600;
  color: var(--text-muted);
  background: var(--bg-tertiary);
  border-radius: 2px;
}

.node-name {
  font-size: 0.8rem;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tree-node.selected .node-name {
  color: var(--accent);
}

.explorer-footer {
  padding: 0.75rem 1rem;
  border-top: 1px solid var(--border-color);
}

.btn-disconnect {
  width: 100%;
  padding: 0.5rem;
  background: var(--bg-hover);
  border: 1px solid var(--border-color);
  border-radius: 6px;
  color: var(--text-secondary);
  font-size: 0.8rem;
  cursor: pointer;
}

.btn-disconnect:hover {
  background: var(--error-bg);
  color: var(--error);
  border-color: var(--error);
}

/* Code Viewer */
.code-viewer {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.placeholder {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  gap: 1rem;
}

.placeholder h3 {
  margin: 0;
  color: var(--text-primary);
}

.placeholder p {
  margin: 0;
  font-size: 0.9rem;
}

.file-view {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.file-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1rem;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border-color);
}

.file-path {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.125rem;
}

.path-segment {
  font-size: 0.85rem;
  color: var(--text-secondary);
}

.path-segment:last-child {
  color: var(--text-primary);
  font-weight: 500;
}

.separator {
  color: var(--text-muted);
  margin: 0 0.125rem;
}

.language-badge {
  padding: 0.25rem 0.5rem;
  background: var(--accent-muted);
  color: var(--accent);
  border-radius: 4px;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
}

.code-container {
  flex: 1;
  overflow: auto;
  background: var(--bg-primary);
}

.loading {
  padding: 2rem;
  text-align: center;
  color: var(--text-muted);
}

.code-content {
  display: flex;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  line-height: 1.6;
}

.line-numbers {
  display: flex;
  flex-direction: column;
  padding: 1rem 0.75rem;
  background: var(--bg-secondary);
  color: var(--text-muted);
  text-align: right;
  user-select: none;
  border-right: 1px solid var(--border-color);
  position: sticky;
  left: 0;
}

.line-numbers span {
  font-size: 0.75rem;
}

.code-text {
  margin: 0;
  padding: 1rem;
  flex: 1;
  overflow-x: auto;
  color: var(--text-primary);
  white-space: pre;
  tab-size: 2;
}

.code-text code {
  font-family: inherit;
}

/* Responsive */
@media (max-width: 768px) {
  .source-page {
    flex-direction: column;
  }

  .sidebar {
    width: 100%;
    max-height: 50vh;
    border-right: none;
    border-bottom: 1px solid var(--border-color);
  }
}
</style>
