import { EventEmitter } from '@angular/core'
import { BehaviorSubject, Subject } from 'rxjs'
import { AppService } from './app.service'

/**
 * AppService's constructor subscribes to several emitters/subjects (see
 * subscribe() and the persistSelectedTheme check) and startUpData() touches
 * a handful of methods on each collaborator — these stubs cover exactly
 * that surface, not the full real services (no TestBed/DI needed, same
 * plain-instantiation-with-stubs precedent as va-filter.service.spec.ts).
 */
const buildDeps = () => {
  const licenceService: any = {
    isAppActivated: new BehaviorSubject<boolean | null>(null),
    activation: jasmine.createSpy('activation').and.resolveTo(undefined)
  }
  const eventService: any = {
    showInfoModal: jasmine.createSpy('showInfoModal'),
    startupDataLoaded: jasmine.createSpy('startupDataLoaded'),
    toggleDarkMode: jasmine.createSpy('toggleDarkMode')
  }
  const sasService: any = {
    loadStartupServiceEmitter: new EventEmitter<any>(),
    requestSiteIdEmitter: new EventEmitter<string>(),
    request: jasmine.createSpy('request')
  }
  const loggerService: any = {
    log: jasmine.createSpy('log')
  }
  const appSettingsService: any = {
    settings: new BehaviorSubject({ persistSelectedTheme: false } as any)
  }
  const router: any = {
    events: new Subject(),
    url: '',
    navigateByUrl: jasmine.createSpy('navigateByUrl')
  }
  const appStoreService: any = {
    getDcAdapterSettings: () => undefined
  }

  return {
    licenceService,
    eventService,
    sasService,
    loggerService,
    appSettingsService,
    router,
    appStoreService
  }
}

const buildAppService = (deps: ReturnType<typeof buildDeps>) =>
  new AppService(
    deps.licenceService,
    deps.eventService,
    deps.sasService,
    deps.loggerService,
    deps.appSettingsService,
    deps.router,
    deps.appStoreService
  )

// Minimal valid startupservice payload — just enough to pass startUpData()'s
// missing-props check (Globvars/Sasdatasets/Saslibs/XLMaps).
const validStartupResponse = () => ({
  adapterResponse: {
    SYSSITE: 'SITE1',
    globvars: [{ ISADMIN: false, DC_ADMIN_GROUP: '', DCLIB: 'DCLIB' }],
    sasdatasets: [],
    saslibs: {},
    xlmaps: []
  }
})

describe('AppService - startup retry', () => {
  it('retries once and succeeds without showing the error modal when only the first attempt rejects', async () => {
    const deps = buildDeps()
    deps.sasService.request.and.returnValues(
      Promise.reject('timeout'),
      Promise.resolve(validStartupResponse())
    )

    const appService = buildAppService(deps)
    // Keep the retry pause instant in tests — see STARTUP_RETRY_PLAN.md.
    ;(appService as any).retryOptions = {
      wait: () => Promise.resolve(),
      random: () => 0
    }

    await appService.startUpData()

    expect(deps.sasService.request).toHaveBeenCalledTimes(2)
    expect(deps.eventService.showInfoModal).not.toHaveBeenCalled()
    expect(deps.eventService.startupDataLoaded).toHaveBeenCalled()
  })

  it('shows the error modal once (not twice) when both attempts reject', async () => {
    const deps = buildDeps()
    deps.sasService.request.and.returnValues(
      Promise.reject('timeout-1'),
      Promise.reject('timeout-2')
    )

    const appService = buildAppService(deps)
    ;(appService as any).retryOptions = {
      wait: () => Promise.resolve(),
      random: () => 0
    }

    await appService.startUpData()

    expect(deps.sasService.request).toHaveBeenCalledTimes(2)
    expect(deps.eventService.showInfoModal).toHaveBeenCalledTimes(1)
    expect(deps.licenceService.isAppActivated.value).toBeFalse()
  })

  it('does not retry a response that arrives but is missing required properties', async () => {
    const deps = buildDeps()
    deps.sasService.request.and.resolveTo({
      adapterResponse: {
        SYSSITE: 'SITE1',
        // globvars deliberately omitted
        sasdatasets: [],
        saslibs: {},
        xlmaps: []
      }
    })

    const appService = buildAppService(deps)
    ;(appService as any).retryOptions = {
      wait: () => Promise.resolve(),
      random: () => 0
    }

    await appService.startUpData()

    expect(deps.sasService.request).toHaveBeenCalledTimes(1)
    expect(deps.eventService.showInfoModal).toHaveBeenCalledTimes(1)
  })
})
