<!-- src/views/pages/saas/SubscriptionHealthPage.vue -->
<script setup>
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
import { useRouter } from 'vue-router'
import { supabase } from '@/lib/supabase/client'
import { useToast } from 'primevue/usetoast'
import { useConfirm } from 'primevue/useconfirm'

import TabView from 'primevue/tabview'
import TabPanel from 'primevue/tabpanel'
import Message from 'primevue/message'

const router = useRouter()
const toast = useToast()
const confirm = useConfirm()

const loading = ref(false)
const fixing = ref(false)
const fixingOwner = ref(null)
const isFetching = ref(false)

const activeTab = ref(0) // 0 = terapeutas, 1 = clínicas

const q = ref('')

const personalRows = ref([]) // v_subscription_feature_mismatch
const clinicRows = ref([]) // v_tenant_feature_exceptions

// -----------------------------
// Labels / Severities
// -----------------------------
function severityForMismatch (t) {
  if (t === 'missing_entitlement') return 'danger'
  if (t === 'unexpected_entitlement') return 'warning'
  return 'secondary'
}

function labelForMismatch (t) {
  if (t === 'missing_entitlement') return 'Faltando'
  if (t === 'unexpected_entitlement') return 'Inesperado'
  return t || '—'
}

function helpForMismatch (t) {
  if (t === 'missing_entitlement') return 'O plano exige, mas não está ativo'
  if (t === 'unexpected_entitlement') return 'Está ativo, mas não consta no plano'
  return ''
}

function severityForException () {
  return 'info'
}

function labelForException (t) {
  if (t === 'commercial_exception') return 'Exceção comercial'
  return t || 'Exceção'
}

function helpForException () {
  return 'Feature liberada manualmente fora do plano (exceção controlada)'
}

// -----------------------------
// Computeds (Terapeutas)
// -----------------------------
const totalPersonal = computed(() => personalRows.value.length)
const totalPersonalMissing = computed(() => personalRows.value.filter(r => r.mismatch_type === 'missing_entitlement').length)
const totalPersonalUnexpected = computed(() => personalRows.value.filter(r => r.mismatch_type === 'unexpected_entitlement').length)
const totalPersonalWithoutOwner = computed(() => personalRows.value.filter(r => !r.owner_id).length)

// -----------------------------
// Computeds (Clínicas)
// -----------------------------
const totalClinic = computed(() => clinicRows.value.length)

// -----------------------------
// Search filtering
// -----------------------------
const filteredPersonal = computed(() => {
  const term = String(q.value || '').trim().toLowerCase()
  if (!term) return personalRows.value

  return personalRows.value.filter(r =>
    String(r.owner_id || '').toLowerCase().includes(term) ||
    String(r.feature_key || '').toLowerCase().includes(term) ||
    String(r.mismatch_type || '').toLowerCase().includes(term)
  )
})

const filteredClinic = computed(() => {
  const term = String(q.value || '').trim().toLowerCase()
  if (!term) return clinicRows.value

  return clinicRows.value.filter(r =>
    String(r.tenant_id || '').toLowerCase().includes(term) ||
    String(r.tenant_name || '').toLowerCase().includes(term) ||
    String(r.plan_key || '').toLowerCase().includes(term) ||
    String(r.feature_key || '').toLowerCase().includes(term) ||
    String(r.exception_type || '').toLowerCase().includes(term)
  )
})

// -----------------------------
// Fetch
// -----------------------------
async function fetchPersonal () {
  const { data, error } = await supabase
    .from('v_subscription_feature_mismatch')
    .select('*')

  if (error) throw error

  personalRows.value = (data || []).map(r => ({
    ...r,
    __rowKey: `${r.owner_id || 'no_owner'}|${r.feature_key || 'no_feature'}|${r.mismatch_type || 'no_type'}`
  }))
}

async function fetchClinic () {
  const { data, error } = await supabase
    .from('v_tenant_feature_exceptions')
    .select('*')

  if (error) throw error

  clinicRows.value = (data || []).map(r => ({
    ...r,
    __rowKey: `${r.tenant_id || 'no_tenant'}|${r.feature_key || 'no_feature'}|${r.exception_type || 'no_type'}`
  }))
}

async function fetchAll () {
  if (isFetching.value) return
  isFetching.value = true
  loading.value = true

  try {
    await Promise.all([fetchPersonal(), fetchClinic()])
  } catch (e) {
    toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || String(e), life: 5000 })
  } finally {
    loading.value = false
    isFetching.value = false
  }
}

async function reloadActiveTab () {
  if (isFetching.value) return
  isFetching.value = true
  loading.value = true

  try {
    if (activeTab.value === 0) await fetchPersonal()
    else await fetchClinic()
  } catch (e) {
    toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || String(e), life: 5000 })
  } finally {
    loading.value = false
    isFetching.value = false
  }
}

// -----------------------------
// Navigation helpers
// -----------------------------
async function inferOwnerKey (ownerId) {
  if (!ownerId) return null

  try {
    const { data, error } = await supabase
      .from('tenants')
      .select('id')
      .eq('id', ownerId)
      .maybeSingle()

    if (!error && data?.id) return `clinic:${ownerId}`
  } catch (_) {}

  try {
    const { data, error } = await supabase
      .from('tenant_members')
      .select('tenant_id')
      .eq('tenant_id', ownerId)
      .limit(1)

    if (!error && Array.isArray(data) && data.length) return `clinic:${ownerId}`
  } catch (_) {}

  return `therapist:${ownerId}`
}

async function openOwnerSubscriptions (ownerId) {
  if (!ownerId) {
    toast.add({
      severity: 'warn',
      summary: 'Owner ausente',
      detail: 'Esta linha está sem owner_id. Verifique dados inconsistentes.',
      life: 4200
    })
    return
  }

  const key = await inferOwnerKey(ownerId)
  router.push({ path: '/saas/subscriptions', query: { q: key || ownerId } })
}

function openClinicSubscriptions (tenantId) {
  if (!tenantId) return
  router.push({ path: '/saas/subscriptions', query: { q: `clinic:${tenantId}` } })
}

// -----------------------------
// Fix (Terapeutas)
// -----------------------------
function askFixOwner (ownerId) {
  if (!ownerId) {
    toast.add({
      severity: 'warn',
      summary: 'Owner ausente',
      detail: 'Não é possível corrigir um owner vazio.',
      life: 4500
    })
    return
  }

  confirm.require({
    header: 'Confirmar correção',
    message: `Reconstruir entitlements para este owner?\n\n${ownerId}\n\nIsso recalcula os recursos ativos com base no plano atual.`,
    icon: 'pi pi-exclamation-triangle',
    acceptClass: 'p-button-danger',
    accept: () => fixOwner(ownerId)
  })
}

async function fixOwner (ownerId) {
  if (!ownerId) return

  fixing.value = true
  fixingOwner.value = ownerId

  try {
    const { error } = await supabase.rpc('rebuild_owner_entitlements', {
      p_owner_id: ownerId
    })
    if (error) throw error

    toast.add({
      severity: 'success',
      summary: 'Corrigido',
      detail: 'Entitlements reconstruídos para este owner.',
      life: 2500
    })

    await fetchPersonal()
  } catch (e) {
    toast.add({
      severity: 'error',
      summary: 'Erro ao corrigir owner',
      detail: e?.message || String(e),
      life: 5200
    })
  } finally {
    fixing.value = false
    fixingOwner.value = null
  }
}

function askFixAll () {
  if (!totalPersonal.value) return

  confirm.require({
    header: 'Confirmar correção geral',
    message: `Reconstruir entitlements para TODOS os owners com divergência?\n\nTotal: ${totalPersonal.value}\n\nObs.: linhas sem owner_id indicam dado inconsistente.`,
    icon: 'pi pi-exclamation-triangle',
    acceptClass: 'p-button-danger',
    accept: () => fixAll()
  })
}

async function fixAll () {
  fixing.value = true
  try {
    const { error } = await supabase.rpc('fix_all_subscription_mismatches')
    if (error) throw error

    toast.add({
      severity: 'success',
      summary: 'Correção aplicada',
      detail: 'Entitlements reconstruídos para todos os owners com divergência.',
      life: 3000
    })

    await fetchPersonal()
  } catch (e) {
    toast.add({
      severity: 'error',
      summary: 'Erro ao corrigir tudo',
      detail: e?.message || String(e),
      life: 5200
    })
  } finally {
    fixing.value = false
  }
}

// -----------------------------
// Exceptions (Clínicas)
// -----------------------------
function askRemoveException (tenantId, featureKey) {
  if (!tenantId || !featureKey) return

  confirm.require({
    header: 'Remover exceção',
    message: `Desativar a exceção desta clínica?\n\nTenant: ${tenantId}\nFeature: ${featureKey}\n\nIsso desliga a liberação manual fora do plano.`,
    icon: 'pi pi-exclamation-triangle',
    acceptClass: 'p-button-danger',
    accept: () => removeException(tenantId, featureKey)
  })
}

async function removeException (tenantId, featureKey) {
  fixing.value = true

  try {
    const { error } = await supabase.rpc('set_tenant_feature_exception', {
      p_tenant_id: tenantId,
      p_feature_key: featureKey,
      p_enabled: false,
      p_reason: 'Remoção via Saúde das Assinaturas'
    })
    if (error) throw error

    toast.add({
      severity: 'success',
      summary: 'Exceção removida',
      detail: 'A liberação manual foi desativada para esta feature.',
      life: 2800
    })

    await fetchClinic()
  } catch (e) {
    toast.add({
      severity: 'error',
      summary: 'Erro ao remover exceção',
      detail: e?.message || String(e),
      life: 5200
    })
  } finally {
    fixing.value = false
  }
}

// -------------------------
// Hero sticky
// -------------------------
const heroRef = ref(null)
const sentinelRef = ref(null)
const heroStuck = ref(false)
let heroObserver = null
const mobileMenuRef = ref(null)

const heroMenuItems = computed(() => [
  {
    label: 'Recarregar aba',
    icon: 'pi pi-refresh',
    command: reloadActiveTab,
    disabled: loading.value || fixing.value
  },
  {
    label: 'Recarregar tudo',
    icon: 'pi pi-sync',
    command: fetchAll,
    disabled: loading.value || fixing.value
  },
  ...(activeTab.value === 0 && totalPersonal.value > 0 ? [{
    label: 'Corrigir tudo (terapeutas)',
    icon: 'pi pi-wrench',
    command: askFixAll,
    disabled: loading.value || fixing.value
  }] : [])
])

onMounted(() => {
  fetchAll()

  if (sentinelRef.value) {
    heroObserver = new IntersectionObserver(
      ([entry]) => { heroStuck.value = !entry.isIntersecting },
      { rootMargin: `${document.querySelector('.l2-main') ? '0px' : '-56px'} 0px 0px 0px`, threshold: 0 }
    )
    heroObserver.observe(sentinelRef.value)
  }
})

onBeforeUnmount(() => {
  heroObserver?.disconnect()
})
</script>

<template>
  <Toast />
  <ConfirmDialog />

  <!-- Sentinel -->
  <div ref="sentinelRef" class="h-px" />

  <!-- Hero sticky -->
  <div
    ref="heroRef"
    class="sticky mx-3 md:mx-4 mb-4 z-20 overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5"
    :style="{ top: 'var(--layout-sticky-top, 56px)' }"
  >
    <div class="absolute inset-0 pointer-events-none overflow-hidden" aria-hidden="true">
      <div class="absolute rounded-full blur-[70px] w-72 h-72 -top-16 -right-20 bg-indigo-400/10" />
      <div class="absolute rounded-full blur-[70px] w-80 h-80 top-10 -left-24 bg-emerald-400/10" />
      <div class="absolute rounded-full blur-[70px] w-72 h-72 -bottom-20 right-24 bg-fuchsia-400/10" />
    </div>
    <div class="relative z-10 flex items-center justify-between gap-3 flex-wrap">
      <div class="min-w-0">
        <div class="text-[1rem] font-bold tracking-tight text-[var(--text-color)]">Saúde das Assinaturas</div>
        <div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Terapeutas: divergências entre plano (esperado) e entitlements (atual). Clínicas: exceções comerciais (features liberadas manualmente fora do plano).</div>
      </div>

      <!-- Ações desktop (≥ 1200px) -->
      <div class="hidden xl:flex items-center gap-2 shrink-0">
        <Button
          label="Recarregar"
          icon="pi pi-refresh"
          severity="secondary"
          outlined
          size="small"
          :loading="loading"
          :disabled="fixing"
          @click="reloadActiveTab"
        />
        <Button
          label="Recarregar tudo"
          icon="pi pi-sync"
          severity="secondary"
          outlined
          size="small"
          :loading="loading"
          :disabled="fixing"
          @click="fetchAll"
        />
        <Button
          v-if="activeTab === 0 && totalPersonal > 0"
          label="Corrigir tudo (terapeutas)"
          icon="pi pi-wrench"
          severity="danger"
          size="small"
          :loading="fixing"
          :disabled="loading"
          @click="askFixAll"
        />
      </div>

      <!-- Ações mobile (< 1200px) -->
      <div class="flex xl:hidden shrink-0">
        <Button
          label="Ações"
          icon="pi pi-ellipsis-v"
          severity="warn"
          size="small"
          @click="(e) => mobileMenuRef.toggle(e)"
        />
        <Menu ref="mobileMenuRef" :model="heroMenuItems" popup />
      </div>
    </div>
  </div>

  <!-- content -->
  <div class="px-3 md:px-4 pb-8 flex flex-col gap-4">
    <!-- busca -->
    <div>
      <FloatLabel variant="on" class="w-full">
        <IconField class="w-full">
          <InputIcon class="pi pi-search" />
          <InputText
            v-model="q"
            id="health_search"
            class="w-full pr-10"
            variant="filled"
            :disabled="loading || fixing"
            autocomplete="off"
          />
        </IconField>
        <label for="health_search">Buscar...</label>
      </FloatLabel>
    </div>

    <TabView v-model:activeIndex="activeTab">
      <!-- ===================================================== -->
      <!-- Terapeutas (Personal) -->
      <!-- ===================================================== -->
      <TabPanel header="Terapeutas (Pessoal)">
        <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-3 mb-4">
          <div class="flex flex-wrap gap-2 items-center justify-content-between">
            <div class="flex gap-2 items-center flex-wrap">
              <Tag :value="`Divergências: ${totalPersonal}`" severity="secondary" />
              <Tag :value="`Faltando: ${totalPersonalMissing}`" severity="danger" />
              <Tag :value="`Inesperado: ${totalPersonalUnexpected}`" severity="warning" />
              <Tag v-if="totalPersonalWithoutOwner > 0" :value="`Sem owner: ${totalPersonalWithoutOwner}`" severity="warn" />
            </div>

            <div class="text-[1rem] text-[var(--text-color-secondary)]">
              <span class="font-medium">Faltando</span>: o plano exige, mas não está ativo ·
              <span class="font-medium">Inesperado</span>: está ativo sem constar no plano
            </div>
          </div>
        </div>

        <DataTable
          :value="filteredPersonal"
          dataKey="__rowKey"
          :loading="loading"
          stripedRows
          responsiveLayout="scroll"
          sortField="owner_id"
          :sortOrder="1"
        >
          <Column header="Owner (User)" style="min-width: 22rem">
            <template #body="{ data }">
              <div class="flex items-center justify-between gap-2">
                <span class="font-medium">
                  {{ data.owner_id || '—' }}
                </span>
                <Tag v-if="!data.owner_id" value="Sem owner" severity="warn" rounded />
              </div>
            </template>
          </Column>

          <Column header="Recurso" style="min-width: 18rem">
            <template #body="{ data }">
              <div class="flex flex-col">
                <span class="font-medium">{{ data.feature_key }}</span>
                <div class="text-[1rem] text-[var(--text-color-secondary)]">
                  {{ helpForMismatch(data.mismatch_type) || '—' }}
                </div>
              </div>
            </template>
          </Column>

          <Column header="Tipo" style="width: 12rem">
            <template #body="{ data }">
              <Tag :severity="severityForMismatch(data.mismatch_type)" :value="labelForMismatch(data.mismatch_type)" />
            </template>
          </Column>

          <Column header="Ações" style="min-width: 20rem">
            <template #body="{ data }">
              <div class="flex gap-2 flex-wrap">
                <Button
                  icon="pi pi-external-link"
                  severity="secondary"
                  outlined
                  v-tooltip.top="data.owner_id ? 'Abrir assinaturas deste owner (com filtro)' : 'Owner ausente'"
                  :disabled="loading || fixing || !data.owner_id"
                  @click="openOwnerSubscriptions(data.owner_id)"
                />

                <Button
                  label="Corrigir owner"
                  icon="pi pi-wrench"
                  severity="danger"
                  outlined
                  v-tooltip.top="data.owner_id ? 'Reconstruir entitlements deste owner' : 'Owner ausente'"
                  :loading="fixing && fixingOwner === data.owner_id"
                  :disabled="loading || !data.owner_id || (fixing && fixingOwner !== data.owner_id)"
                  @click="askFixOwner(data.owner_id)"
                />
              </div>
            </template>
          </Column>
        </DataTable>

        <Divider class="my-5" />

        <Message severity="info" class="mt-4">
          <div class="text-[1rem] line-height-3">
            <div class="mb-0">
              <span class="font-semibold">Dica:</span>
              Se você alterar o plano e o acesso não refletir imediatamente, esta aba exibirá as divergências entre o plano ativo e os entitlements atuais.
              A ação <span class="font-medium">Corrigir</span> reconstrói os entitlements do owner com base no plano vigente e elimina inconsistências.
            </div>
          </div>
        </Message>
      </TabPanel>

      <!-- ===================================================== -->
      <!-- Clínicas (Tenant) -->
      <!-- ===================================================== -->
      <TabPanel header="Clínicas (Exceções)">
        <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-3 mb-4">
          <div class="flex flex-wrap gap-2 items-center justify-content-between">
            <div class="flex gap-2 items-center flex-wrap">
              <Tag :value="`Exceções ativas: ${totalClinic}`" severity="info" />
            </div>

            <div class="text-[1rem] text-[var(--text-color-secondary)]">
              Exceções comerciais: features liberadas manualmente fora do plano. Útil para testes, suporte e acordos.
            </div>
          </div>
        </div>

        <DataTable
          :value="filteredClinic"
          dataKey="__rowKey"
          :loading="loading"
          stripedRows
          responsiveLayout="scroll"
          sortField="tenant_id"
          :sortOrder="1"
        >
          <Column header="Clínica (Tenant)" style="min-width: 22rem">
            <template #body="{ data }">
              <div class="flex flex-col">
                <span class="font-medium">{{ data.tenant_name || data.tenant_id }}</span>
                <div class="text-[1rem] text-[var(--text-color-secondary)]">{{ data.tenant_name ? data.tenant_id : '—' }}</div>
              </div>
            </template>
          </Column>

          <Column header="Plano" style="width: 12rem">
            <template #body="{ data }">
              <Tag :value="data.plan_key || '—'" severity="secondary" />
            </template>
          </Column>

          <Column header="Feature" style="min-width: 18rem">
            <template #body="{ data }">
              <div class="flex flex-col">
                <span class="font-medium">{{ data.feature_key }}</span>
                <div class="text-[1rem] text-[var(--text-color-secondary)]">
                  {{ helpForException() }}
                </div>
              </div>
            </template>
          </Column>

          <Column header="Tipo" style="width: 14rem">
            <template #body="{ data }">
              <Tag :severity="severityForException()" :value="labelForException(data.exception_type)" />
            </template>
          </Column>

          <Column header="Ações" style="min-width: 22rem">
            <template #body="{ data }">
              <div class="flex gap-2 flex-wrap">
                <Button
                  icon="pi pi-external-link"
                  severity="secondary"
                  outlined
                  v-tooltip.top="'Abrir assinaturas desta clínica (com filtro)'"
                  :disabled="loading || fixing || !data.tenant_id"
                  @click="openClinicSubscriptions(data.tenant_id)"
                />

                <Button
                  label="Remover exceção"
                  icon="pi pi-ban"
                  severity="danger"
                  outlined
                  v-tooltip.top="'Desativar a liberação manual desta feature'"
                  :disabled="loading || fixing || !data.tenant_id || !data.feature_key"
                  @click="askRemoveException(data.tenant_id, data.feature_key)"
                />
              </div>
            </template>
          </Column>
        </DataTable>

        <Divider class="my-5" />

        <Message severity="info" class="mt-4">
          <div class="text-[1rem] line-height-3">
            <div class="mb-2">
              <span class="font-semibold">Observação:</span>
              Exceção é uma escolha de negócio. Quando ativa, pode liberar acesso mesmo que o plano não permita.
              Utilize <span class="font-medium">Remover exceção</span> quando a liberação deixar de fazer sentido.
            </div>

            <div class="mb-0">
              <span class="font-semibold">Dica:</span>
              Exceções comerciais liberam recursos fora do plano.
              Se o acesso não refletir como esperado, verifique se existe uma exceção ativa para esta clínica.
              A ação <span class="font-medium">Remover exceção</span> restaura o comportamento estritamente definido pelo plano.
            </div>
          </div>
        </Message>
      </TabPanel>
    </TabView>
  </div>
</template>
