import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import {
  isParentAuthenticated,
  isParentPersistent,
  parentAuthExpiresAt,
  authenticateParent,
  logoutParent,
  loginUser,
} from '../auth'

// Stub window.location
const locationStub = { href: '', pathname: '/', assign: vi.fn(), replace: vi.fn(), reload: vi.fn() }
Object.defineProperty(window, 'location', { value: locationStub, writable: true })

// Build a stateful localStorage stub and register it via vi.stubGlobal so it is
// visible to auth.ts's module scope (not just the test file's scope).
function makeLocalStorageStub() {
  const store: Record<string, string> = {}
  return {
    getItem: (key: string) => store[key] ?? null,
    setItem: (key: string, value: string) => {
      store[key] = value
    },
    removeItem: (key: string) => {
      delete store[key]
    },
    clear: () => {
      for (const k of Object.keys(store)) delete store[k]
    },
    _store: store,
  }
}

const localStorageStub = makeLocalStorageStub()
vi.stubGlobal('localStorage', localStorageStub)

describe('auth store - parent mode expiry', () => {
  beforeEach(() => {
    vi.useFakeTimers()
    localStorageStub.clear()
    logoutParent()
  })

  afterEach(() => {
    logoutParent()
    vi.useRealTimers()
  })

  describe('non-persistent mode', () => {
    it('authenticateParent(false) sets isParentAuthenticated to true', () => {
      authenticateParent(false)
      expect(isParentAuthenticated.value).toBe(true)
      expect(isParentPersistent.value).toBe(false)
    })

    it('non-persistent auth does not set isParentPersistent', () => {
      authenticateParent(false)
      expect(isParentPersistent.value).toBe(false)
      expect(parentAuthExpiresAt.value).not.toBeNull()
      // Confirm the expiry is ~1 minute, not 2 days
      expect(parentAuthExpiresAt.value!).toBeLessThan(Date.now() + 172_800_000)
    })

    it('isParentAuthenticated becomes false after 1 minute (watcher fires)', () => {
      authenticateParent(false)
      expect(isParentAuthenticated.value).toBe(true)
      // Advance 60s: watcher fires every 15s, at t=60000 Date.now() >= expiresAt
      vi.advanceTimersByTime(60_001)
      expect(isParentAuthenticated.value).toBe(false)
    })

    it('isParentAuthenticated is still true just before 1 minute', () => {
      authenticateParent(false)
      vi.advanceTimersByTime(59_999)
      // Watcher last fired at t=45000, next fires at t=60000 — hasn't expired yet
      expect(isParentAuthenticated.value).toBe(true)
    })
  })

  describe('persistent mode', () => {
    it('authenticateParent(true) sets isParentAuthenticated to true', () => {
      authenticateParent(true)
      expect(isParentAuthenticated.value).toBe(true)
      expect(isParentPersistent.value).toBe(true)
    })

    it('writes expiresAt to localStorage for persistent auth — parentAuthExpiresAt is set to ~2 days', () => {
      const before = Date.now()
      authenticateParent(true)
      const after = Date.now()
      // Verify the expiry ref is populated and within the 2-day window
      expect(parentAuthExpiresAt.value).not.toBeNull()
      expect(parentAuthExpiresAt.value!).toBeGreaterThanOrEqual(before + 172_800_000)
      expect(parentAuthExpiresAt.value!).toBeLessThanOrEqual(after + 172_800_000)
    })

    it('isParentAuthenticated becomes false after 2 days (watcher fires)', () => {
      authenticateParent(true)
      expect(isParentAuthenticated.value).toBe(true)
      vi.advanceTimersByTime(172_800_001)
      expect(isParentAuthenticated.value).toBe(false)
    })

    it('isParentAuthenticated is still true just before 2 days', () => {
      authenticateParent(true)
      // Advance to just before expiry; watcher last fired at t=172_785_000
      vi.advanceTimersByTime(172_784_999)
      expect(isParentAuthenticated.value).toBe(true)
    })
  })

  describe('logoutParent()', () => {
    it('clears isParentAuthenticated and isParentPersistent', () => {
      authenticateParent(true)
      expect(isParentAuthenticated.value).toBe(true)
      logoutParent()
      expect(isParentAuthenticated.value).toBe(false)
      expect(isParentPersistent.value).toBe(false)
    })

    it('removing auth clears expiresAt and persistent flag', () => {
      authenticateParent(true)
      expect(parentAuthExpiresAt.value).not.toBeNull()
      logoutParent()
      expect(parentAuthExpiresAt.value).toBeNull()
      expect(isParentPersistent.value).toBe(false)
    })

    it('clears parentAuthExpiresAt', () => {
      authenticateParent(false)
      logoutParent()
      expect(parentAuthExpiresAt.value).toBeNull()
    })
  })

  describe('loginUser()', () => {
    it('loginUser() clears parent auth entirely', () => {
      authenticateParent(true)
      expect(isParentAuthenticated.value).toBe(true)
      loginUser()
      expect(isParentAuthenticated.value).toBe(false)
      expect(isParentPersistent.value).toBe(false)
      expect(parentAuthExpiresAt.value).toBeNull()
    })
  })

  describe('localStorage restore on init', () => {
    it('expired localStorage entry is cleaned up when checked', () => {
      // Simulate a stored entry that is already expired
      const expired = Date.now() - 1000
      localStorage.setItem('parentAuth', JSON.stringify({ expiresAt: expired }))

      // Mirroring the init logic in auth.ts: read, check, remove if stale
      const stored = localStorage.getItem('parentAuth')
      if (stored) {
        const parsed = JSON.parse(stored) as { expiresAt: number }
        if (!parsed.expiresAt || Date.now() >= parsed.expiresAt) {
          localStorage.removeItem('parentAuth')
        }
      }

      expect(localStorage.getItem('parentAuth')).toBeNull()
    })
  })
})
