<template>
  <div>
    <div class="page-header">
      <div class="page-title">
        <h2>Tables</h2>
        <span class="subtitle">Create and manage PostgreSQL tables in the public schema</span>
      </div>
      <NychButton @click="showCreate = true" label="+ New Table" />
    </div>

    <div class="table-card">
      <div class="table-card-header">
        <span class="count">{{ tables.length }} {{ tables.length === 1 ? 'table' : 'tables' }}</span>
      </div>
      <div v-if="loading" class="loading-overlay">
        <div class="loading-spinner"></div>
        <span>Loading…</span>
      </div>
      <template v-else-if="tables.length"><div class="table-scroll"><table class="data-table">
        <thead>
          <tr>
            <th>Name</th>
            <th>Columns</th>
            <th>Actions</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="t in tables" :key="t.table_name">
            <td class="name-cell"><code>{{ t.table_name }}</code></td>
            <td class="count-cell">{{ t.column_count }}</td>
            <td class="actions-cell">
              <NychButton size="small" severity="secondary" @click="openInspect(t.table_name)" label="Inspect" />
              <NychButton size="small" severity="danger" @click="openDropPreview(t.table_name)" label="Drop" />
            </td>
          </tr>
        </tbody>
      </table></div></template>
      <div class="empty-state" v-else>
        <span class="empty-icon">▦</span>
        <span class="empty-label">No tables yet</span>
        <span class="empty-hint">Create a table to start storing data via the CRUD API.</span>
      </div>
    </div>

    <!-- Create Table Dialog -->
    <NychDialog v-model:visible="showCreate" header="New Table" :modal="true" :draggable="false" style="width: min(700px, 95vw)">
      <form @submit.prevent="submitCreate" class="dialog-form">
        <div class="field">
          <label>Table Name</label>
          <NychInputText v-model="createForm.name" placeholder="my_table" fluid autocomplete="off" />
          <p class="hint">Lowercase letters, numbers, and underscores only.</p>
        </div>

        <div class="columns-section">
          <div class="columns-header">
            <label>Columns</label>
            <NychButton type="button" size="small" @click="addColumn" label="+ Add Column" />
          </div>
          <div class="hint fixed-col-hint">An <code>id SERIAL PRIMARY KEY</code> column is always added automatically.</div>

          <div class="column-row header-row">
            <span>Name</span>
            <span>Type</span>
            <span>Nullable</span>
            <span></span>
          </div>

          <div v-for="(col, i) in createForm.columns" :key="i" class="column-row">
            <NychInputText v-model="col.name" placeholder="column_name" fluid />
            <NychSelect
              v-model="col.col_type"
              :options="COLUMN_TYPES"
              fluid
            />
            <div class="nullable-toggle">
              <input type="checkbox" v-model="col.nullable" :id="`nullable-${i}`" />
              <label :for="`nullable-${i}`">Yes</label>
            </div>
            <button type="button" class="remove-btn" @click="removeColumn(i)">✕</button>
          </div>

          <div class="empty-columns" v-if="createForm.columns.length === 0">
            <span>Add at least one column.</span>
          </div>
        </div>

        <NychButton type="submit" fluid :disabled="!canSubmitCreate" label="Create Table" />
      </form>
    </NychDialog>

    <!-- Inspect Dialog (read-only) -->
    <NychDialog v-model:visible="showInspect" :header="`Inspect — ${inspectPreview?.table_name ?? ''}`" :modal="true" :draggable="false" style="width: min(760px, 95vw)">
      <div v-if="inspectLoading" class="preview-loading">Loading table data…</div>
      <div v-else-if="inspectPreview" class="preview-body">
        <div class="preview-meta">
          <div class="meta-row">
            <span class="meta-label">Table</span>
            <code class="meta-value">{{ inspectPreview.table_name }}</code>
          </div>
          <div class="meta-row">
            <span class="meta-label">Rows</span>
            <span class="meta-value">{{ inspectPreview.row_count.toLocaleString() }}</span>
          </div>
          <div class="meta-row">
            <span class="meta-label">CRUD endpoint</span>
            <code class="meta-value endpoint">/api/{{ inspectPreview.table_name }}</code>
          </div>
        </div>

        <div class="schema-section">
          <div class="section-label">Schema</div>
          <table class="schema-table">
            <thead>
              <tr>
                <th>Column</th>
                <th>Type</th>
                <th>Nullable</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="col in inspectPreview.columns" :key="col.column_name">
                <td><code>{{ col.column_name }}</code></td>
                <td><span class="type-badge">{{ col.data_type }}</span></td>
                <td>{{ col.is_nullable === 'YES' ? 'yes' : 'no' }}</td>
              </tr>
            </tbody>
          </table>
        </div>

        <div class="sample-section" v-if="inspectPreview.sample_rows.length > 0">
          <div class="section-label">
            Sample data
            <span class="sample-count">(first {{ inspectPreview.sample_rows.length }} of {{ inspectPreview.row_count.toLocaleString() }})</span>
          </div>
          <div class="sample-scroll">
            <table class="data-table sample-table">
              <thead>
                <tr>
                  <th v-for="col in inspectPreview.columns" :key="col.column_name">{{ col.column_name }}</th>
                </tr>
              </thead>
              <tbody>
                <tr v-for="(row, i) in inspectPreview.sample_rows" :key="i">
                  <td v-for="col in inspectPreview.columns" :key="col.column_name">
                    {{ row[col.column_name] ?? '—' }}
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </div>
        <div class="empty-state sample-empty" v-else>
          <span class="empty-icon">▦</span>
          <span class="empty-label">Empty table</span>
          <span class="empty-hint">Use <code>POST /api/{{ inspectPreview.table_name }}</code> to insert rows.</span>
        </div>
      </div>
    </NychDialog>

    <!-- Drop Preview Dialog -->
    <NychDialog v-model:visible="showDropPreview" header="Drop Table" :modal="true" :draggable="false" style="width: min(760px, 95vw)">
      <div v-if="dropPreviewLoading" class="preview-loading">Loading table data…</div>
      <div v-else-if="dropPreview" class="preview-body">
        <div class="preview-meta">
          <div class="meta-row">
            <span class="meta-label">Table</span>
            <code class="meta-value">{{ dropPreview.table_name }}</code>
          </div>
          <div class="meta-row">
            <span class="meta-label">Rows</span>
            <span class="meta-value row-count" :class="dropPreview.row_count > 0 ? 'has-data' : 'no-data'">
              {{ dropPreview.row_count.toLocaleString() }}
            </span>
          </div>
        </div>

        <div class="warning-banner" v-if="dropPreview.row_count > 0">
          ⚠ This table contains {{ dropPreview.row_count.toLocaleString() }} {{ dropPreview.row_count === 1 ? 'row' : 'rows' }} that will be permanently deleted.
        </div>

        <div class="schema-section">
          <div class="section-label">Schema</div>
          <table class="schema-table">
            <thead>
              <tr>
                <th>Column</th>
                <th>Type</th>
                <th>Nullable</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="col in dropPreview.columns" :key="col.column_name">
                <td><code>{{ col.column_name }}</code></td>
                <td><span class="type-badge">{{ col.data_type }}</span></td>
                <td>{{ col.is_nullable === 'YES' ? 'yes' : 'no' }}</td>
              </tr>
            </tbody>
          </table>
        </div>

        <div class="sample-section" v-if="dropPreview.sample_rows.length > 0">
          <div class="section-label">
            Sample data
            <span class="sample-count">(first {{ dropPreview.sample_rows.length }} of {{ dropPreview.row_count.toLocaleString() }})</span>
          </div>
          <div class="sample-scroll">
            <table class="data-table sample-table">
              <thead>
                <tr>
                  <th v-for="col in dropPreview.columns" :key="col.column_name">{{ col.column_name }}</th>
                </tr>
              </thead>
              <tbody>
                <tr v-for="(row, i) in dropPreview.sample_rows" :key="i">
                  <td v-for="col in dropPreview.columns" :key="col.column_name">
                    {{ row[col.column_name] ?? '—' }}
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </div>

        <div class="confirm-section">
          <label class="confirm-label">Type <strong>{{ dropPreview.table_name }}</strong> to confirm:</label>
          <NychInputText v-model="dropConfirmName" :placeholder="dropPreview.table_name" fluid />
        </div>

        <div class="drop-actions">
          <NychButton severity="secondary" @click="showDropPreview = false" label="Cancel" />
          <NychButton severity="danger" :disabled="dropConfirmName !== dropPreview.table_name" @click="confirmDrop" label="Drop Table" />
        </div>
      </div>
    </NychDialog>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { useAuthStore } from '../../stores/auth'

const auth = useAuthStore()

const COLUMN_TYPES = [
  'TEXT', 'INTEGER', 'BIGINT', 'SMALLINT', 'BOOLEAN',
  'NUMERIC', 'FLOAT4', 'FLOAT8', 'UUID', 'TIMESTAMPTZ', 'DATE', 'JSONB',
]

interface TableInfo {
  table_name: string
  column_count: number
}

interface ColumnInfo {
  column_name: string
  data_type: string
  is_nullable: string
}

interface TablePreview {
  table_name: string
  row_count: number
  columns: ColumnInfo[]
  sample_rows: Record<string, unknown>[]
}

interface ColumnDef {
  name: string
  col_type: string
  nullable: boolean
}

const tables = ref<TableInfo[]>([])
const loading = ref(false)

// create
const showCreate = ref(false)
const createForm = ref<{ name: string; columns: ColumnDef[] }>({ name: '', columns: [] })

const canSubmitCreate = computed(
  () => createForm.value.name.trim() !== '' && createForm.value.columns.length > 0,
)

function addColumn() {
  createForm.value.columns.push({ name: '', col_type: 'TEXT', nullable: true })
}

function removeColumn(i: number) {
  createForm.value.columns.splice(i, 1)
}

// inspect
const showInspect = ref(false)
const inspectLoading = ref(false)
const inspectPreview = ref<TablePreview | null>(null)

// drop
const showDropPreview = ref(false)
const dropPreviewLoading = ref(false)
const dropPreview = ref<TablePreview | null>(null)
const dropConfirmName = ref('')

async function load() {
  loading.value = true
  try {
    const res = await fetch('/api/admin/tables', { headers: auth.authHeaders() })
    tables.value = await res.json()
  } finally {
    loading.value = false
  }
}

async function fetchPreview(tableName: string): Promise<TablePreview> {
  const res = await fetch(`/api/admin/tables/${tableName}`, { headers: auth.authHeaders() })
  return res.json()
}

async function submitCreate() {
  const res = await fetch('/api/admin/tables', {
    method: 'POST',
    headers: { ...auth.authHeaders(), 'Content-Type': 'application/json' },
    body: JSON.stringify(createForm.value),
  })
  if (res.ok) {
    const createdName = createForm.value.name
    showCreate.value = false
    createForm.value = { name: '', columns: [] }
    await load()
    // immediately open inspect so the user can verify the new table
    openInspect(createdName)
  }
}

async function openInspect(tableName: string) {
  showInspect.value = true
  inspectLoading.value = true
  inspectPreview.value = null
  inspectPreview.value = await fetchPreview(tableName)
  inspectLoading.value = false
}

async function openDropPreview(tableName: string) {
  showDropPreview.value = true
  dropPreviewLoading.value = true
  dropPreview.value = null
  dropConfirmName.value = ''
  dropPreview.value = await fetchPreview(tableName)
  dropPreviewLoading.value = false
}

async function confirmDrop() {
  if (!dropPreview.value) return
  await fetch(`/api/admin/tables/${dropPreview.value.table_name}`, {
    method: 'DELETE',
    headers: auth.authHeaders(),
  })
  showDropPreview.value = false
  dropPreview.value = null
  load()
}

onMounted(load)
</script>

<style scoped>
.name-cell  { font-family: var(--font-mono); }
.count-cell { color: var(--text-muted); font-family: var(--font-mono); font-size: 0.82rem; }
.actions-cell { display: flex; gap: 0.4rem; }

/* ── Create form ────────────────────────────────── */
.columns-section {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

.columns-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.fixed-col-hint {
  margin-top: -0.25rem;
}

.column-row {
  display: grid;
  grid-template-columns: 1fr 1fr 5rem 2rem;
  gap: 0.5rem;
  align-items: center;
}

.header-row {
  font-size: 0.75rem;
  color: var(--text-dim);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0 0.25rem;
}

.nullable-toggle {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.85rem;
  color: var(--text-muted);
  padding-left: 0.25rem;
}

.remove-btn {
  background: none;
  border: none;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 0.8rem;
  padding: 0.25rem;
  border-radius: 4px;
  line-height: 1;
  transition: color 0.1s, background 0.1s;
}

.remove-btn:hover {
  color: var(--danger);
  background: var(--danger-subtle);
}

.empty-columns {
  font-size: 0.82rem;
  color: var(--text-dim);
  padding: 0.5rem 0.25rem;
}

/* ── Shared preview ─────────────────────────────── */
.preview-loading {
  color: var(--text-muted);
  font-size: 0.9rem;
  padding: 1rem 0;
  text-align: center;
}

.preview-body {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.preview-meta {
  display: flex;
  gap: 2rem;
  flex-wrap: wrap;
}

.meta-row {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.meta-label {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dim);
  font-weight: 600;
}

.meta-value {
  font-size: 1rem;
  color: var(--text-high);
}

.endpoint {
  font-size: 0.85rem;
  color: var(--primary);
}

.row-count.has-data { color: var(--danger); font-weight: 700; }
.row-count.no-data  { color: var(--success); }

.warning-banner {
  background: var(--danger-subtle);
  border: 1px solid var(--danger-border);
  color: var(--danger);
  border-radius: 6px;
  padding: 0.65rem 0.9rem;
  font-size: 0.85rem;
  font-weight: 500;
}

.section-label {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dim);
  margin-bottom: 0.4rem;
}

.sample-count {
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  color: var(--text-muted);
}

.schema-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.83rem;
}

.schema-table th,
.schema-table td {
  padding: 0.35rem 0.6rem;
  border-bottom: 1px solid var(--border-lo);
  text-align: left;
}

.schema-table th {
  color: var(--text-dim);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.type-badge {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  background: var(--surface-2);
  border: 1px solid var(--border-lo);
  border-radius: 4px;
  padding: 0.1rem 0.4rem;
  color: var(--text-label);
}

.sample-scroll {
  overflow-x: auto;
  max-height: 200px;
  overflow-y: auto;
  border: 1px solid var(--border-lo);
  border-radius: 6px;
}

.sample-table {
  min-width: 100%;
}

.sample-empty {
  padding: 1.5rem;
  border: 1px dashed var(--border-lo);
  border-radius: 8px;
}

/* ── Drop confirm ───────────────────────────────── */
.confirm-section {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.confirm-label {
  font-size: 0.85rem;
  color: var(--text-label);
}

.drop-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  padding-top: 0.25rem;
}
</style>
