<template>
  <div class="page-wrap">

    <!-- ===== TOP BAR ===== -->
    <div class="topbar">
      <button class="btn-invite" @click="openInviteDialog">Invite Client</button>

      <div class="topbar-right">
        <div class="search-wrap">
          <input
            v-model="search"
            type="text"
            class="search-input"
            placeholder="Search Client"
            @input="handleSearch"
          />
          <button v-if="search" class="clear-btn" @click="search = ''; handleSearch()">×</button>
          <svg class="search-icon" viewBox="0 0 20 20" fill="none">
            <circle cx="9" cy="9" r="6" stroke="#9CA3AF" stroke-width="1.5"/>
            <path d="M13.5 13.5L17 17" stroke="#9CA3AF" stroke-width="1.5" stroke-linecap="round"/>
          </svg>
        </div>

        <!-- Filters: chỉ hiện ở active/suspended -->
        <div v-if="tab !== 'pending'" class="filter-wrap">
          <div class="filter-field">
            <label>Filter by status</label>
            <select v-model="filterStatus" @change="handleFilterChange">
              <option value="active">Active</option>
              <option value="suspended">Suspended</option>
            </select>
            <svg class="chevron" viewBox="0 0 10 6" fill="none">
              <path d="M1 1l4 4 4-4" stroke="#6B7280" stroke-width="1.4" stroke-linecap="round"/>
            </svg>
          </div>

          <div class="filter-field">
            <label>Filter by plan type</label>
            <select v-model="filterPlan" @change="handleFilterChange">
              <option value="">All</option>
              <option v-for="app in APP_LIST" :key="app.value" :value="app.value">
                {{ app.title }}
              </option>
            </select>
            <svg class="chevron" viewBox="0 0 10 6" fill="none">
              <path d="M1 1l4 4 4-4" stroke="#6B7280" stroke-width="1.4" stroke-linecap="round"/>
            </svg>
          </div>

          <div class="filter-field">
            <label>Filter by billing cycle</label>
            <select v-model="filterBilling" @change="handleFilterChange">
              <option value="">All</option>
              <option value="monthly">Monthly</option>
              <option value="yearly">Yearly</option>
            </select>
            <svg class="chevron" viewBox="0 0 10 6" fill="none">
              <path d="M1 1l4 4 4-4" stroke="#6B7280" stroke-width="1.4" stroke-linecap="round"/>
            </svg>
          </div>
        </div>
      </div>
    </div>

    <!-- ===== TABLE CARD ===== -->
    <div class="table-card">

      <!-- Toolbar row -->
      <div class="toolbar">
        <div class="toolbar-left">
          <button class="refresh-btn" :class="{ spinning: loading }" @click="handleRefresh">
            <svg viewBox="0 0 18 18" fill="none" width="15" height="15">
              <path d="M15.5 9A6.5 6.5 0 1 1 9 2.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
              <path d="M9 0.5v3.5l3-1.75L9 0.5z" fill="currentColor"/>
            </svg>
          </button>
        </div>
        <div class="toolbar-right">
          <span class="page-range-text">{{ pageRange }}</span>
          <button class="page-btn" :disabled="page <= 1" @click="handleUpdatePage(page - 1)">
            <svg viewBox="0 0 7 11" fill="none" width="7" height="11">
              <path d="M6 1L1.5 5.5 6 10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
            </svg>
          </button>
          <button class="page-btn" :disabled="page >= pages" @click="handleUpdatePage(page + 1)">
            <svg viewBox="0 0 7 11" fill="none" width="7" height="11">
              <path d="M1 1l4.5 4.5L1 10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
            </svg>
          </button>
        </div>
      </div>

      <!-- Tabs -->
      <div class="tabs-row">
        <button class="tab" :class="{ active: tab === 'active' }" @click="onTabChange('active')">Active</button>
        <button class="tab" :class="{ active: tab === 'suspended' }" @click="onTabChange('suspended')">Suspended</button>
        <button class="tab" :class="{ active: tab === 'pending' }" @click="onTabChange('pending')">Pending Invitation</button>
      </div>

      <!-- Loading bar -->
      <div v-if="loading" class="loading-bar"><div class="loading-bar-fill" /></div>

      <!-- TABLE: active / suspended -->
      <div v-if="tab !== 'pending'" class="table-scroll">
        <table>
          <thead>
            <tr>
              <th>Organization Name</th>
              <th>Email</th>
              <th>Sites</th>
              <th>Plan Type</th>
              <th>Billing Cycle</th>
              <th>Subscription Start</th>
              <th>Subscription End</th>
              <th>Status</th>
              <th>Actions</th>
            </tr>
          </thead>
          <tbody>
            <tr v-if="!loading && items.length === 0">
              <td colspan="9" class="empty">No records found.</td>
            </tr>
            <tr v-for="item in items" :key="item._id">
              <td class="td-name">{{ item.name }}</td>
              <td class="td-muted">{{ item.email }}</td>
              <td>
                <span class="sites-badge">{{ item.sites }}</span>
              </td>
              <td>{{ item.planType }}</td>
              <td class="td-muted">{{ item.billingCycle }}</td>
              <td>
                <span class="date-cell">
                  <svg viewBox="0 0 16 16" fill="none" width="13" height="13">
                    <rect x="1" y="3" width="14" height="12" rx="2" stroke="#9CA3AF" stroke-width="1.3"/>
                    <path d="M1 7h14" stroke="#9CA3AF" stroke-width="1.3"/>
                    <path d="M5 1v3M11 1v3" stroke="#9CA3AF" stroke-width="1.3" stroke-linecap="round"/>
                  </svg>
                  {{ item.subscriptionStart }}
                </span>
              </td>
              <td>
                <span class="date-cell">
                  <svg viewBox="0 0 16 16" fill="none" width="13" height="13">
                    <rect x="1" y="3" width="14" height="12" rx="2" stroke="#9CA3AF" stroke-width="1.3"/>
                    <path d="M1 7h14" stroke="#9CA3AF" stroke-width="1.3"/>
                    <path d="M5 1v3M11 1v3" stroke="#9CA3AF" stroke-width="1.3" stroke-linecap="round"/>
                  </svg>
                  {{ item.subscriptionEnd }}
                </span>
              </td>
              <td>
                <span :class="['status-chip', item.status]">{{ item.status }}</span>
              </td>
              <td>
                <div class="action-wrap">
                  <button class="dots-btn" @click.stop="toggleMenu(item._id)">
                    <span /><span /><span />
                  </button>
                  <div v-if="openMenuId === item._id" class="dropdown">
                    <button class="dd-item" @click="closeMenu">Edit</button>
                    <button class="dd-item danger" @click="closeMenu">
                      {{ item.status === 'suspended' ? 'Reactivate' : 'Suspend' }}
                    </button>
                  </div>
                </div>
              </td>
            </tr>
          </tbody>
        </table>
      </div>

      <!-- TABLE: pending -->
      <div v-else class="table-scroll">
        <table>
          <thead>
            <tr>
              <th>Email</th>
              <th>App</th>
              <th>Role</th>
              <th>Status</th>
              <th>Action</th>
            </tr>
          </thead>
          <tbody>
            <tr v-if="!loading && items.length === 0">
              <td colspan="5" class="empty">No pending invitations.</td>
            </tr>
            <tr v-for="item in items" :key="item._id">
              <td class="td-muted">{{ item.email }}</td>
              <td>{{ item.app }}</td>
              <td class="td-muted">{{ item.role }}</td>
              <td><span class="status-chip pending">{{ item.status }}</span></td>
              <td>
                <button
                  class="cancel-btn"
                  :disabled="cancelLoadingId === item._id"
                  @click="cancelInvite(item)"
                >
                  <span v-if="cancelLoadingId === item._id" class="spinner" />
                  <span v-else>Cancel Invite</span>
                </button>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>

    <!-- ===== DIALOG ===== -->
    <div v-if="dialog" class="overlay" @click.self="dialog = false">
      <div class="dialog-box">
        <InvitationClientForm title="Invite Client" @success="handleSuccess" @cancel="dialog = false" />
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, nextTick, onMounted, ref, watch } from 'vue'
import useOrg from '../composables/useOrg'
import useVerification from '../composables/useVerification'
import useRole from '../composables/useRole'
import InvitationClientForm from './InvitationClientForm.vue'
import useCustomerSite from '../composables/useCustomerSite'
import useSubscription from '../composables/useSubscription'

/* ── TYPES ── */
type TabStatus = 'active' | 'suspended' | 'pending'

/* ── COMPOSABLES ── */
const { getOrganizationsWithSubscription } = useOrg()
const { getVerifications, cancelUserInvitation } = useVerification()
const { getCustomerSites: getCustomerSitesByOrgId } = useCustomerSite()
const { getByOrgId: getSubscriptionByOrgId } = useSubscription()
const { getRoleById } = useRole()

/* ── CONSTANTS ── */
const APP_LIST = [
  { title: 'Organization',                     value: 'organization' },
  { title: 'Security Agency',                  value: 'security_agency' },
  { title: 'Cleaning Services',                value: 'cleaning_services' },
  { title: 'Property Management Agency',       value: 'property_management_agency' },
  { title: 'Mechanical & Electrical Services', value: 'mechanical_electrical_services' },
  { title: 'Pest Control Services',            value: 'pest_control_services' },
  { title: 'Landscaping Services',             value: 'landscaping_services' },
  { title: 'Pool Maintenance Services',        value: 'pool_maintenance_services' },
]

/* ── STATE ── */
const tab             = ref<TabStatus>('active')
const dialog          = ref(false)
const openMenuId      = ref<string | null>(null)
// filterStatus
const filterStatus    = ref<'active' | 'suspended'>('active')
const filterPlan      = ref('')   // '' = All | any APP_LIST value
const filterBilling   = ref('')   // '' = All | 'monthly' | 'yearly'

const items           = ref<any[]>([])
const loading         = ref(false)
const page            = ref(1)
const pages           = ref(1)
const search          = ref('')
const totalItems      = ref(0)
const cancelLoadingId = ref<string | null>(null)
const limit           = ref(10)
const roleCache       = ref<Record<string, string>>({})

/* ── COMPUTED ── */
const pageRange = computed(() => {
  if (!totalItems.value) return '0-0 of 0'
  const start = (page.value - 1) * limit.value + 1
  const end   = Math.min(page.value * limit.value, totalItems.value)
  return `${start}-${end} of ${totalItems.value}`
})

/* ── HELPERS ── */
function formatDate(date?: string | Date) {
  if (date == null || date === '') return '-'
  const d = date instanceof Date ? date : new Date(date as string)
  return isNaN(d.getTime()) ? '-' : d.toLocaleDateString('en-US')
}

function planTypeLabel(sub: Record<string, any>) {
  if (!sub) return '-'
  if (sub.paidType) return String(sub.paidType)
  if (sub.type === 'organization') return 'Organization'
  if (sub.type === 'affiliate')    return 'Affiliate'
  const desc = String(sub.description || '').trim()
  return desc ? (desc.length > 48 ? `${desc.slice(0, 45)}…` : desc) : '-'
}

async function resolveRoleName(id: string) {
  if (!id) return '-'
  if (roleCache.value[id]) return roleCache.value[id]
  const res  = await getRoleById(id)
  const name = res?.name ?? '-'
  roleCache.value[id] = name
  return name
}

function parseTotalItems(pageRangeStr: string, fallback: number): number {
  const match = pageRangeStr?.match(/of\s+(\d+)/i)
  return match ? Number(match[1]) : fallback
}


async function fetchOrgs(status: 'active' | 'suspended') {
  loading.value = true

  try {
    const res = await getOrganizationsWithSubscription({
      page: page.value,
      search: search.value,
      limit: limit.value,
      status,
      type: filterPlan.value,
      billingCycle: filterBilling.value,
    })

    const orgs = res?.data?.items ?? res?.items ?? []

    const siteCache: Record<string, number> = {}

    items.value = await Promise.all(
      orgs.map(async (org: any) => {
        const sub = org?.subscription ?? {}

        let siteCount = siteCache[org._id]

        if (siteCount === undefined) {
          const sitesRes = await getCustomerSitesByOrgId(org._id)

          siteCount =
            sitesRes?.items?.length ??
            sitesRes?.data?.items?.length ??
            0

          siteCache[org._id] = siteCount
        }

        return {
          _id: org._id,

          name: org.name,
          email: org.email,
          nature: org.nature,

          sites: `${siteCount} Sites`,

          planType: planTypeLabel(sub),

          billingCycle: sub?.billingCycle ?? "-",

          subscriptionStart: formatDate(sub?.createdAt),

          subscriptionEnd: formatDate(sub?.nextBillingDate),

          status: org?.status ?? status,
        }
      })
    )

    pages.value = res?.pages ?? 1

    totalItems.value = parseTotalItems(
      res?.pageRange,
      items.value.length
    )
  } finally {
    loading.value = false
  }
}

async function fetchPending() {
  const res = await getVerifications({
    status: 'pending',
    type:   'user-invite',
    page:   page.value,
    search: search.value,
    email: search.value,
  })

  items.value = await Promise.all(
    (res?.items ?? []).map(async (i: any) => ({
      ...i,
      app:  APP_LIST.find(a => a.value === i.metadata?.app)?.title ?? i.metadata?.app ?? '-',
      role: await resolveRoleName(i.metadata?.role),
    }))
  )
  pages.value      = res?.pages ?? 1
  totalItems.value = parseTotalItems(res?.pageRange, items.value.length)
}

async function fetchData() {
  loading.value = true
  try {
    if (tab.value === 'pending') {
      await fetchPending()
    } else {
      await fetchOrgs(tab.value)
    }
  } finally {
    loading.value = false
  }
}

/* ── WATCH: filterStatus ── */
watch(filterStatus, (val) => {
  tab.value  = val
  page.value = 1
  fetchData()
})

/* ── EVENTS ── */
async function handleUpdatePage(p: number) {
  page.value = p
  await fetchData()
}

async function onTabChange(value: TabStatus) {
  tab.value  = value
  // sync filterStatus ( active/suspended)
  if (value !== 'pending') filterStatus.value = value
  page.value = 1
  await fetchData()
}

function handleRefresh() {
  fetchData()
}

let searchTimeout: ReturnType<typeof setTimeout> | null = null
function handleSearch() {
  if (searchTimeout) clearTimeout(searchTimeout)
  searchTimeout = setTimeout(() => {
    page.value = 1
    fetchData()
  }, 300)
}

function handleFilterChange() {

  page.value = 1
  fetchData()
}

/* ── MENU ── */
function toggleMenu(id: string) {
  openMenuId.value = openMenuId.value === id ? null : id
}
function closeMenu() {
  openMenuId.value = null
}

/* ── DIALOG ── */
function openInviteDialog() { dialog.value = true }
function handleSuccess()    { dialog.value = false; fetchData() }

/* ── CANCEL INVITE ── */
async function cancelInvite(item: any) {
  try {
    cancelLoadingId.value = item._id
    await cancelUserInvitation(item._id)
    await fetchData()
  } finally {
    cancelLoadingId.value = null
  }
}

onMounted(() => fetchData())
</script>

<style scoped>
* { box-sizing: border-box; margin: 0; padding: 0; }

.page-wrap {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 14px;
  color: #111827;
  background: transparent;
}

/* ===== TOPBAR ===== */
.topbar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  background: transparent;
}
.topbar-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 12px;
}
.btn-invite {
  background: #fff;
  color: #111827;
  border: 1px solid #D1D5DB;
  border-radius: 24px;
  padding: 10px 22px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s;
}
.btn-invite:hover { background: #F9FAFB; }

.search-wrap {
  position: relative;
  width: 260px;
  flex-shrink: 0;
}
.search-input {
  width: 100%;
  height: 36px;
  border: 1px solid #E5E7EB;
  border-radius: 8px;
  padding: 0 34px 0 12px;
  font-size: 13px;
  color: #111827;
  background: #fff;
  outline: none;
}
.search-input:focus { border-color: #9CA3AF; }
.search-input::placeholder { color: #9CA3AF; }
.search-icon {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  width: 15px;
  height: 15px;
  pointer-events: none;
}
.clear-btn {
  position: absolute;
  right: 32px;
  top: 50%;
  transform: translateY(-50%);
  border: none;
  background: transparent;
  color: #9CA3AF;
  font-size: 16px;
  cursor: pointer;
  line-height: 1;
  padding: 0;
}
.clear-btn:hover { color: #374151; }

.filter-wrap {
  display: flex;
  gap: 10px;
  flex-shrink: 0;
}
.filter-field {
  position: relative;
  display: flex;
  flex-direction: column;
}
.filter-field label {
  position: absolute;
  top: -8px;
  left: 9px;
  font-size: 10px;
  color: #6B7280;
  background: #fff;
  padding: 0 3px;
  pointer-events: none;
  z-index: 1;
  white-space: nowrap;
}
.filter-field select {
  height: 36px;
  border: 1px solid #E5E7EB;
  border-radius: 8px;
  padding: 0 28px 0 10px;
  font-size: 13px;
  color: #111827;
  background: #fff;
  appearance: none;
  cursor: pointer;
  outline: none;
  min-width: 110px;
}
.filter-field select:focus { border-color: #9CA3AF; }
.chevron {
  position: absolute;
  right: 9px;
  top: 50%;
  transform: translateY(-50%);
  width: 10px;
  height: 6px;
  pointer-events: none;
}

/* ===== TABLE CARD ===== */
.table-card {
  margin: 12px 0 0 0;
  background: #fff;
  border: 1px solid #E5E7EB;
  border-radius: 10px;
  overflow: hidden;
}

/* ===== TOOLBAR ===== */
.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 12px;
  background: #fff;
  border-bottom: 1px solid #F3F4F6;
}
.toolbar-left { display: flex; align-items: center; }
.toolbar-right { display: flex; align-items: center; gap: 6px; }

.refresh-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: #6B7280;
  width: 28px;
  height: 28px;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.15s;
}
.refresh-btn:hover { background: #F3F4F6; }
.refresh-btn.spinning svg { animation: spin 0.8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

.page-range-text { font-size: 12px; color: #6B7280; }
.page-btn {
  background: none;
  border: 1px solid #E5E7EB;
  border-radius: 5px;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: #374151;
  transition: background 0.1s;
}
.page-btn:hover:not(:disabled) { background: #F3F4F6; }
.page-btn:disabled { opacity: 0.35; cursor: not-allowed; }

/* ===== TABS ===== */
.tabs-row {
  display: flex;
  border-bottom: 1px solid #E5E7EB;
  padding: 0 16px;
}
.tab {
  padding: 10px 14px;
  font-size: 13px;
  color: #6B7280;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  margin-bottom: -1px;
  transition: color 0.15s, border-color 0.15s;
}
.tab:hover { color: #374151; }
.tab.active { color: #111827; border-bottom-color: #111827; font-weight: 500; }

/* ===== LOADING BAR ===== */
.loading-bar { height: 2px; background: #F3F4F6; overflow: hidden; }
.loading-bar-fill {
  height: 100%;
  width: 35%;
  background: #6B7280;
  animation: slide 1.1s ease-in-out infinite;
}
@keyframes slide {
  0%   { transform: translateX(-150%); }
  100% { transform: translateX(400%); }
}

/* ===== TABLE ===== */
.table-scroll { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
thead th {
  padding: 10px 16px;
  text-align: left;
  font-weight: 600;
  font-size: 13px;
  color: #374151;
  border-bottom: 1px solid #E5E7EB;
  white-space: nowrap;
  background: #fff;
}
tbody tr { border-bottom: 1px solid #F3F4F6; transition: background 0.1s; }
tbody tr:last-child { border-bottom: none; }
tbody tr:hover { background: #FAFAFA; }
tbody td { padding: 14px 16px; vertical-align: middle; }

.empty { text-align: center; color: #9CA3AF; padding: 48px 0 !important; }
.td-name { font-weight: 500; color: #111827; }
.td-muted { color: #6B7280; font-size: 13px; }

.sites-badge {
  display: inline-block;
  background: #F3F4F6;
  border-radius: 20px;
  padding: 3px 12px;
  font-size: 12px;
  color: #374151;
}
.date-cell {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 13px;
  color: #374151;
}

/* ===== STATUS CHIPS ===== */
.status-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border-radius: 20px;
  padding: 4px 12px;
  font-size: 12px;
  font-weight: 500;
}
.status-chip::before { content: ''; width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
.status-chip.active    { background: #D1FAE5; color: #065F46; }
.status-chip.active::before    { background: #10B981; }
.status-chip.suspended { background: #FEE2E2; color: #991B1B; }
.status-chip.suspended::before { background: #EF4444; }
.status-chip.pending   { background: #FEF9C3; color: #854D0E; }
.status-chip.pending::before   { background: #EAB308; }

/* ===== ACTION MENU ===== */
.action-wrap { position: relative; }
.dots-btn {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  background: none;
  border: none;
  border-radius: 6px;
  padding: 6px 8px;
  cursor: pointer;
  color: #9CA3AF;
  transition: background 0.15s;
}
.dots-btn:hover { background: #F3F4F6; color: #374151; }
.dots-btn span { display: block; width: 4px; height: 4px; border-radius: 50%; background: currentColor; }

.dropdown {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  background: #fff;
  border: 1px solid #E5E7EB;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
  min-width: 130px;
  z-index: 50;
  overflow: hidden;
}
.dd-item {
  display: block;
  width: 100%;
  padding: 9px 14px;
  font-size: 13px;
  text-align: left;
  background: none;
  border: none;
  cursor: pointer;
  color: #374151;
  transition: background 0.1s;
}
.dd-item:hover { background: #F9FAFB; }
.dd-item.danger { color: #DC2626; }
.dd-item.danger:hover { background: #FEF2F2; }

/* ===== CANCEL INVITE ===== */
.cancel-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px;
  font-size: 12px;
  color: #DC2626;
  background: #FEF2F2;
  border: 1px solid #FECACA;
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.15s;
}
.cancel-btn:hover { background: #FEE2E2; }
.cancel-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.spinner {
  display: inline-block;
  width: 11px;
  height: 11px;
  border: 1.5px solid #FECACA;
  border-top-color: #DC2626;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}

/* ===== DIALOG ===== */
.overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}
.dialog-box {
  background: #fff;
  border-radius: 12px;
  max-width: 500px;
  width: 90%;
  box-shadow: 0 16px 48px rgba(0,0,0,0.12);
  overflow: hidden;
}
</style>
