import { describe, expect, it } from 'vitest';

import type { Features, SiteSummary } from '@/types';

import {
  buildHref,
  getVisibleAccountItems,
  getVisibleSiteNavItems,
  siteNavItems,
} from './navigation';

const baseFeatures: Features = {
  billing: true,
  socialAuth: false,
  emailVerification: false,
  apiTokens: true,
  userSettings: true,
  notifications: true,
  onboarding: false,
  apiDocs: false,
  twoFactor: false,
  webhooks: false,
  admin: false,
  dataExport: false,
  referrals: false,
  portfolio: false,
  teams: false,
  siteMembers: false,
};

const site: SiteSummary = {
  id: '42',
  name: 'heatware.net',
  domain: 'heatware.net',
  has_gsc: true,
  gsc_synced: true,
  has_wp: true,
  wp_connected: true,
  has_analysis: true,
  has_reviewed_recommendation: true,
  has_ai_key: true,
  ai_available: true,
  has_ga4: false,
  onboarding_completed: true,
  current_role: 'owner',
};

describe('navigation — siteNavItems', () => {
  it('exposes exactly 5 hub items in canonical order', () => {
    const keys = siteNavItems.map((item) => item.key);
    expect(keys).toEqual(['overview', 'opportunities', 'content', 'performance', 'settings']);
  });

  it('every site item has a routeName (no raw href)', () => {
    siteNavItems.forEach((item) => {
      expect(item.kind).toBe('site');
      expect(item.routeName).toBeTruthy();
    });
  });

  // Persona contract (B1): the v1 persona is solo (docs/PERSONA_V1.md), so the
  // default Settings destination must be a real site-settings surface, NEVER the
  // team/members seat-management page.
  it('routes Settings to the General settings surface, not team/members', () => {
    const settings = siteNavItems.find((item) => item.key === 'settings');
    expect(settings?.routeName).toBe('sites.settings.general');
    expect(settings?.routeName).not.toBe('site-members.index');
  });
});

describe('navigation — buildHref', () => {
  it('resolves site items against the active site id', () => {
    const item = siteNavItems[0]; // overview → analyze.index
    const href = buildHref(item, site);
    expect(href).toBe('/sites/42/analyze');
  });

  it('returns null for site items when no current site', () => {
    const item = siteNavItems[0];
    expect(buildHref(item, null)).toBeNull();
  });

  it('resolves account items via routeName when present', () => {
    const billing = {
      kind: 'account' as const,
      key: 'billing',
      label: 'Billing',
      icon: siteNavItems[0].icon,
      routeName: 'billing.index',
    };
    expect(buildHref(billing, null)).toBe('/billing');
  });

  it('falls back to literal href on account items without routeName', () => {
    const tokens = {
      kind: 'account' as const,
      key: 'tokens',
      label: 'API Tokens',
      icon: siteNavItems[0].icon,
      href: '/settings/tokens',
    };
    expect(buildHref(tokens, null)).toBe('/settings/tokens');
  });
});

describe('navigation — getVisibleSiteNavItems', () => {
  it('returns nothing when no site is selected (empty-state contract)', () => {
    const items = getVisibleSiteNavItems(baseFeatures, null);
    expect(items).toHaveLength(0);
  });

  it('returns all 5 items when a site is selected and no flag gates', () => {
    const items = getVisibleSiteNavItems(baseFeatures, site);
    expect(items).toHaveLength(5);
  });
});

describe('navigation — getVisibleAccountItems', () => {
  it('hides billing when feature flag is off', () => {
    const items = getVisibleAccountItems({ ...baseFeatures, billing: false });
    expect(items.find((i) => i.key === 'billing')).toBeUndefined();
  });

  it('hides API tokens when feature flag is off', () => {
    const items = getVisibleAccountItems({ ...baseFeatures, apiTokens: false });
    expect(items.find((i) => i.key === 'api-tokens')).toBeUndefined();
  });

  it('returns billing + tokens when both flags are on', () => {
    const items = getVisibleAccountItems(baseFeatures);
    expect(items.map((i) => i.key)).toContain('billing');
    expect(items.map((i) => i.key)).toContain('api-tokens');
  });
});
