import { beforeEach, describe, expect, it, vi } from 'vitest'

vi.mock('../../lib/prisma', () => ({
  prisma: {
    menuItem: {
      findMany: vi.fn(),
    },
    employee: {
      findUniqueOrThrow: vi.fn(),
    },
    company: {
      findUniqueOrThrow: vi.fn(),
    },
    auditLog: {
      create: vi.fn(),
    },
    $transaction: vi.fn(),
  },
}))

import { prisma } from '../../lib/prisma'
import { getEmployeeMenu, previewCompanyMenu } from './menu.service'

describe('menu.service', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })

  it('builds the employee menu from subscription defaults and company overrides', async () => {
    vi.mocked(prisma.employee.findUniqueOrThrow).mockResolvedValue({
      id: 'employee_1',
      role: 'MANAGER',
      isActive: true,
      companyId: 'company_1',
    } as never)

    vi.mocked(prisma.company.findUniqueOrThrow).mockResolvedValue({
      id: 'company_1',
      name: 'Atlas Cars',
      status: 'ACTIVE',
      subscription: { plan: 'GROWTH', status: 'ACTIVE' },
    } as never)

    vi.mocked(prisma.menuItem.findMany).mockResolvedValue([
      {
        id: 'item_dashboard',
        systemKey: 'dashboard',
        label: 'Dashboard',
        itemType: 'INTERNAL_PAGE',
        routeOrUrl: '/',
        icon: 'LayoutDashboard',
        parentId: null,
        openInNewTab: false,
        isRequired: true,
        isActive: true,
        displayOrder: 1,
        roleVisibilities: [{ role: 'MANAGER' }],
        subscriptionAssignments: [],
        companyAssignments: [],
      },
      {
        id: 'item_reports',
        systemKey: 'reports',
        label: 'Reports',
        itemType: 'INTERNAL_PAGE',
        routeOrUrl: '/reports',
        icon: 'BarChart2',
        parentId: null,
        openInNewTab: false,
        isRequired: false,
        isActive: true,
        displayOrder: 80,
        roleVisibilities: [{ role: 'MANAGER' }],
        subscriptionAssignments: [{ plan: 'GROWTH', displayOrder: 80, isActive: true }],
        companyAssignments: [],
      },
      {
        id: 'item_finance',
        systemKey: null,
        label: 'Finance Portal',
        itemType: 'EXTERNAL_LINK',
        routeOrUrl: 'https://finance.example.com',
        icon: null,
        parentId: null,
        openInNewTab: true,
        isRequired: false,
        isActive: true,
        displayOrder: 200,
        roleVisibilities: [{ role: 'MANAGER' }],
        subscriptionAssignments: [],
        companyAssignments: [{ companyId: 'company_1', displayOrder: 5, isActive: true }],
      },
      {
        id: 'item_owner_only',
        systemKey: 'settings',
        label: 'Settings',
        itemType: 'INTERNAL_PAGE',
        routeOrUrl: '/settings',
        icon: 'Settings',
        parentId: null,
        openInNewTab: false,
        isRequired: false,
        isActive: true,
        displayOrder: 150,
        roleVisibilities: [{ role: 'OWNER' }],
        subscriptionAssignments: [{ plan: 'GROWTH', displayOrder: 150, isActive: true }],
        companyAssignments: [],
      },
    ] as never)

    const result = await getEmployeeMenu('employee_1')

    expect(result.items).toHaveLength(3)
    expect(result.items.map((item) => item.label)).toEqual(['Dashboard', 'Finance Portal', 'Reports'])
    expect(result.items[0]).toMatchObject({
      label: 'Dashboard',
      itemType: 'INTERNAL_PAGE',
    })
    expect(result.items[1]).toMatchObject({
      label: 'Finance Portal',
      itemType: 'EXTERNAL_LINK',
      openInNewTab: true,
    })
  })

  it('explains hidden items in preview results', async () => {
    vi.mocked(prisma.company.findUniqueOrThrow).mockResolvedValue({
      id: 'company_1',
      name: 'Atlas Cars',
      status: 'ACTIVE',
      subscription: { plan: 'STARTER', status: 'ACTIVE' },
    } as never)

    vi.mocked(prisma.menuItem.findMany).mockResolvedValue([
      {
        id: 'item_dashboard',
        systemKey: 'dashboard',
        label: 'Dashboard',
        itemType: 'INTERNAL_PAGE',
        routeOrUrl: '/',
        icon: 'LayoutDashboard',
        parentId: null,
        openInNewTab: false,
        isRequired: true,
        isActive: true,
        displayOrder: 1,
        roleVisibilities: [{ role: 'MANAGER' }],
        subscriptionAssignments: [],
        companyAssignments: [],
      },
      {
        id: 'item_reports',
        systemKey: 'reports',
        label: 'Reports',
        itemType: 'INTERNAL_PAGE',
        routeOrUrl: '/reports',
        icon: 'BarChart2',
        parentId: null,
        openInNewTab: false,
        isRequired: false,
        isActive: true,
        displayOrder: 80,
        roleVisibilities: [{ role: 'MANAGER' }],
        subscriptionAssignments: [{ plan: 'GROWTH', displayOrder: 80, isActive: true }],
        companyAssignments: [],
      },
      {
        id: 'item_direct',
        systemKey: null,
        label: 'Finance Portal',
        itemType: 'EXTERNAL_LINK',
        routeOrUrl: 'https://finance.example.com',
        icon: null,
        parentId: null,
        openInNewTab: true,
        isRequired: false,
        isActive: true,
        displayOrder: 20,
        roleVisibilities: [{ role: 'MANAGER' }],
        subscriptionAssignments: [],
        companyAssignments: [{ companyId: 'company_1', displayOrder: 10, isActive: true }],
      },
    ] as never)

    const result = await previewCompanyMenu({ companyId: 'company_1', role: 'MANAGER' })

    expect(result.items.find((item) => item.label === 'Dashboard')).toMatchObject({
      visible: true,
      source: 'subscription',
    })
    expect(result.items.find((item) => item.label === 'Dashboard')?.reasons.join(' ')).toContain('defaults to all subscription plans')
    expect(result.items.find((item) => item.label === 'Finance Portal')).toMatchObject({
      visible: true,
      source: 'company',
    })
    expect(result.items.find((item) => item.label === 'Reports')).toMatchObject({
      visible: false,
    })
    expect(result.items.find((item) => item.label === 'Reports')?.reasons.join(' ')).toContain('STARTER does not include this menu item')
  })

  it('returns the approved seven-item STARTER owner sidebar in order', async () => {
    vi.mocked(prisma.employee.findUniqueOrThrow).mockResolvedValue({
      id: 'employee_1',
      role: 'OWNER',
      isActive: true,
      companyId: 'company_1',
    } as never)

    vi.mocked(prisma.company.findUniqueOrThrow).mockResolvedValue({
      id: 'company_1',
      name: 'Atlas Cars',
      status: 'ACTIVE',
      subscription: { plan: 'STARTER', status: 'ACTIVE' },
    } as never)

    const item = (
      systemKey: string,
      label: string,
      routeOrUrl: string,
      icon: string,
      displayOrder: number,
      plans: string[],
    ) => ({
      id: `item_${systemKey}`,
      systemKey,
      label,
      itemType: 'INTERNAL_PAGE',
      routeOrUrl,
      icon,
      parentId: null,
      openInNewTab: false,
      isRequired: displayOrder <= 70,
      isActive: true,
      displayOrder,
      roleVisibilities: [{ role: 'OWNER' }],
      subscriptionAssignments: plans.map((plan) => ({ plan, displayOrder, isActive: true })),
      companyAssignments: [],
    })

    vi.mocked(prisma.menuItem.findMany).mockResolvedValue([
      item('dashboard', 'Dashboard', '/', 'LayoutDashboard', 10, ['STARTER', 'GROWTH', 'PRO']),
      item('reservations', 'Reservations', '/reservations', 'Calendar', 20, ['STARTER', 'GROWTH', 'PRO']),
      item('fleet', 'Fleet', '/fleet', 'Car', 30, ['STARTER', 'GROWTH', 'PRO']),
      item('customers', 'Customers', '/customers', 'Users', 40, ['STARTER', 'GROWTH', 'PRO']),
      item('reports', 'Reports', '/reports', 'BarChart2', 50, ['STARTER', 'GROWTH', 'PRO']),
      item('billing', 'Billing', '/billing', 'CreditCard', 60, ['STARTER', 'GROWTH', 'PRO']),
      item('settings', 'Settings', '/settings', 'Settings', 70, ['STARTER', 'GROWTH', 'PRO']),
      item('online-reservations', 'Online Reservations', '/online-reservations', 'Globe', 80, ['GROWTH', 'PRO']),
      item('offers', 'Offers', '/offers', 'Tag', 90, ['GROWTH', 'PRO']),
      item('team', 'Team', '/team', 'UserPlus', 100, ['GROWTH', 'PRO']),
      item('contracts', 'Contracts', '/contracts', 'FileText', 110, ['GROWTH', 'PRO']),
      item('notifications', 'Notifications', '/notifications', 'Bell', 120, ['GROWTH', 'PRO']),
      item('reviews', 'Reviews', '/reviews', 'Star', 130, ['PRO']),
      item('complaints', 'Complaints', '/complaints', 'AlertTriangle', 140, ['PRO']),
      { ...item('subscription', 'Subscription', '/subscription', 'CreditCard', 999, []), isActive: false },
    ] as never)

    const result = await getEmployeeMenu('employee_1')

    expect(result.items.map((menuItem) => menuItem.systemKey)).toEqual([
      'dashboard',
      'reservations',
      'fleet',
      'customers',
      'reports',
      'billing',
      'settings',
    ])
  })

  it('returns no feature menu for expired trial subscriptions', async () => {
    vi.mocked(prisma.employee.findUniqueOrThrow).mockResolvedValue({
      id: 'employee_1',
      role: 'OWNER',
      isActive: true,
      companyId: 'company_1',
    } as never)

    vi.mocked(prisma.company.findUniqueOrThrow).mockResolvedValue({
      id: 'company_1',
      name: 'Atlas Cars',
      status: 'TRIALING',
      subscription: { plan: 'STARTER', status: 'EXPIRED' },
    } as never)

    vi.mocked(prisma.menuItem.findMany).mockResolvedValue([
      {
        id: 'item_dashboard',
        systemKey: 'dashboard',
        label: 'Dashboard',
        itemType: 'INTERNAL_PAGE',
        routeOrUrl: '/',
        icon: 'LayoutDashboard',
        parentId: null,
        openInNewTab: false,
        isRequired: true,
        isActive: true,
        displayOrder: 10,
        roleVisibilities: [{ role: 'OWNER' }],
        subscriptionAssignments: [{ plan: 'STARTER', displayOrder: 10, isActive: true }],
        companyAssignments: [],
      },
    ] as never)

    const result = await getEmployeeMenu('employee_1')

    expect(result.subscriptionStatus).toBe('EXPIRED')
    expect(result.subscriptionAccessLevel).toBe('none')
    expect(result.items).toEqual([])
  })

  it('falls back to the baseline feature menu when full-access entitlements only expose dashboard and subscription', async () => {
    vi.mocked(prisma.employee.findUniqueOrThrow).mockResolvedValue({
      id: 'employee_1',
      role: 'OWNER',
      isActive: true,
      companyId: 'company_1',
    } as never)

    vi.mocked(prisma.company.findUniqueOrThrow).mockResolvedValue({
      id: 'company_1',
      name: 'Atlas Cars',
      status: 'TRIALING',
      subscription: { plan: 'STARTER', status: 'TRIALING' },
    } as never)

    vi.mocked(prisma.menuItem.findMany).mockResolvedValue([
      {
        id: 'item_dashboard',
        systemKey: 'dashboard',
        label: 'Dashboard',
        itemType: 'INTERNAL_PAGE',
        routeOrUrl: '/',
        icon: 'LayoutDashboard',
        parentId: null,
        openInNewTab: false,
        isRequired: true,
        isActive: true,
        displayOrder: 10,
        roleVisibilities: [{ role: 'OWNER' }],
        subscriptionAssignments: [{ plan: 'STARTER', displayOrder: 10, isActive: true }],
        companyAssignments: [],
      },
      {
        id: 'item_subscription',
        systemKey: 'subscription',
        label: 'Subscription',
        itemType: 'INTERNAL_PAGE',
        routeOrUrl: '/subscription',
        icon: 'CreditCard',
        parentId: null,
        openInNewTab: false,
        isRequired: false,
        isActive: true,
        displayOrder: 999,
        roleVisibilities: [{ role: 'OWNER' }],
        subscriptionAssignments: [],
        companyAssignments: [],
      },
    ] as never)

    const result = await getEmployeeMenu('employee_1')

    expect(result.subscriptionStatus).toBe('TRIALING')
    expect(result.subscriptionAccessLevel).toBe('full')
    expect(result.items.map((menuItem) => menuItem.systemKey)).toEqual([
      'dashboard',
      'reservations',
      'fleet',
      'customers',
      'reports',
      'billing',
      'settings',
    ])
  })
})
