import { ApiRequestError } from '../../lib/http'
import type {
  AdminDashboardResponse,
  AdminArchivedWinnerItem,
  AdminOptionalFeatureSettingsResponse,
  AdminOperationalSettingsResponse,
  AdminRiskFlag,
  AdminRiskFlagsResponse,
  AdminSeasonDetailResponse,
  AdminSeasonListItem,
  AdminShowactApplicationItem,
  AdminSiteSettingsResponse,
  AdminSponsorItem,
  AdminTrackingRulesResponse,
  AdminWorkflowRulesResponse,
  DatabaseHealthResponse,
  OverviewResponse,
  PublicSponsorsResponse,
  SeasonCategoriesResponse,
  WinnerArchiveResponse,
} from '../../types/awards'

export type ApiMode = 'api' | 'fallback'
export type PublicErrorKind = 'offline' | 'unreachable' | 'server' | null

export function createEmptyOverview(): OverviewResponse {
  return {
    seasonId: 0,
    year: new Date().getFullYear(),
    title: '',
    showDate: '',
    showStartsAt: '20:00:00',
    currentPhase: '',
    isCommunityOnly: true,
    loginProvider: 'Twitch',
    timeline: [],
    featuredCategories: [],
    winnersPreview: [],
    archiveYears: [],
    siteContent: {
      hostDisplayName: '',
      hostTagline: '',
      hostArtistName: '',
      hostImageUrl: '/assets/amaterasu2sei_2.png',
      newsletterUrl: '',
      shareXUrl: '',
      shareDiscordUrl: '',
      privacyEmail: '',
      privacyPolicyContent: '',
      awardsSectionTitle: '',
      awardsSectionDescription: '',
      subcategoriesSectionTitle: '',
      subcategoriesSectionDescription: '',
      streamBanner: {
        eyebrow: 'Das grosse Finale',
        title: 'Award-Show Finale',
        text: 'Finale, Countdown und Stream-Link an einem Ort. Sei live dabei, wenn die Community ihre Stars feiert.',
        liveButtonLabel: 'Jetzt live · Zum Stream',
        liveButtonUrl: '',
        lockedButtonLabel: 'Stream noch gesperrt',
        useCompletedContent: false,
        completedEyebrow: 'Danke fürs Mitfiebern',
        completedTitle: 'Award-Show abgeschlossen',
        completedText: 'Die grosse Award-Show ist vorbei. Danke an alle, die nominiert, gevotet und live mitgefiebert haben.',
        completedButtonLabel: 'Highlights ansehen',
        completedButtonUrl: '',
      },
      socialLinks: [],
      footerLinks: [],
    },
    featureFlags: {
      clipSubmissionsEnabled: false,
      clipReviewEnabled: true,
      clipAdminMenuVisible: true,
      clipSubmissionDisabledMessage: 'Clip-Einreichungen sind aktuell geschlossen.',
      showactApplicationsEnabled: false,
      showactApplicationStartsAt: null,
      showactApplicationEndsAt: null,
      showactApplicationDisabledMessage: 'Showact-Bewerbungen sind aktuell geschlossen.',
      sponsorsVisible: true,
      showactFormSchemaJson: '[]',
    },
    faq: [],
  }
}

export function createEmptyPublicSponsors(year = new Date().getFullYear()): PublicSponsorsResponse {
  return {
    year,
    items: [],
  }
}

export function createEmptyCategories(): SeasonCategoriesResponse {
  return {
    seasonId: 0,
    year: new Date().getFullYear(),
    categories: [],
  }
}

export function createEmptyArchive(year = new Date().getFullYear() - 1): WinnerArchiveResponse {
  return {
    year,
    items: [],
  }
}

export function createEmptyAdminDashboard(): AdminDashboardResponse {
  return {
    seasonId: 0,
    year: 0,
    seasonName: '',
    isCurrent: false,
    metrics: [],
    activities: [],
    topCategories: [],
    riskFlags: [],
    auditEntries: [],
  }
}

export function createEmptyAdminOperationalSettings(): AdminOperationalSettingsResponse {
  return {
    demoLoginManagedByDatabase: false,
    demoLoginEnabled: false,
    demoLoginEmail: '',
    demoLoginPasswordSet: false,
    demoLoginTwitchUserId: '',
    demoLoginDisplayName: '',
    twitchAuthManagedByDatabase: false,
    twitchAuthConfigured: false,
    twitchClientId: '',
    twitchClientSecretSet: false,
    twitchRedirectUri: '',
    twitchScope: '',
    sessionIdleTimeoutHours: 12,
    maintenanceModeEnabled: false,
    maintenanceTitle: 'Sternenpause',
    maintenanceMessage: 'Die Award-Galaxie wird gerade liebevoll poliert. Schau gleich wieder vorbei.',
  }
}

export function createEmptyAdminRiskFlagsResponse(): AdminRiskFlagsResponse {
  return {
    items: [],
    totalCount: 0,
    returnedCount: 0,
    offset: 0,
    limit: 25,
    hasMore: false,
    severityCounts: [],
    statusCounts: [],
  }
}

export function createEmptyAdminWorkflowRulesResponse(): AdminWorkflowRulesResponse {
  return {
    rules: [],
  }
}

export function createEmptyAdminTrackingRulesResponse(): AdminTrackingRulesResponse {
  return {
    source: {
      providerKey: 'twitchtracker',
      providerLabel: 'TwitchTracker Basic API',
      baseUrl: 'https://twitchtracker.com/api',
      notesSummary: '',
      showManualReviewNotesInReview: true,
    },
    importantMetrics: [],
    optionalMetrics: [],
    flags: [],
    manualReviewNotes: '',
  }
}

export function createEmptyAdminSeasonDetail(): AdminSeasonDetailResponse {
  return {
    id: 0,
    year: 0,
    name: '',
    isDemo: false,
    currentPhase: '',
    isCurrent: false,
    isCommunityOnly: true,
    nominationStartsAt: '',
    nominationEndsAt: '',
    votingStartsAt: '',
    votingEndsAt: '',
    reviewStartsAt: '',
    reviewEndsAt: '',
    showDate: '',
    showStartsAt: '20:00:00',
    winnersPublishedAt: null,
    winnersPublishedByTwitchId: null,
    subcategoryTemplates: [],
    categories: [],
    candidates: [],
    pendingNominations: [],
    pendingNominationGroups: [],
    reviewedNominations: [],
    trackingReviewNotes: '',
    showTrackingReviewNotes: true,
    results: [],
    votingWorkspace: {
      summary: {
        totalVotes: 0,
        totalSubcategories: 0,
        votedSubcategories: 0,
        readySubcategories: 0,
        problemSubcategories: 0,
        winnerSetSubcategories: 0,
      },
      categories: [],
    },
    clipSubmissions: [],
  }
}

export function createEmptyAdminSiteSettings(): AdminSiteSettingsResponse {
  return {
    hostDisplayName: '',
    hostTagline: '',
    hostArtistName: '',
    hostImageUrl: '/assets/amaterasu2sei_2.png',
    newsletterUrl: '',
    shareXUrl: '',
    shareDiscordUrl: '',
    privacyEmail: '',
    privacyPolicyContent: '',
    privacyPolicyUpdatedBy: null,
    privacyPolicyUpdatedAt: null,
    imprintUrl: '',
    imprintContent: '',
    contactUrl: '',
    contactContent: '',
    sponsorsUrl: '',
    sponsorsContent: '',
    showactsUrl: '',
    showactsContent: '',
    streamBannerEyebrow: 'Das grosse Finale',
    streamBannerTitle: 'Award-Show Finale',
    streamBannerText: 'Finale, Countdown und Stream-Link an einem Ort. Sei live dabei, wenn die Community ihre Stars feiert.',
    streamBannerLiveButtonLabel: 'Jetzt live · Zum Stream',
    streamBannerLiveButtonUrl: '',
    streamBannerLockedButtonLabel: 'Stream noch gesperrt',
    streamBannerUseCompletedContent: false,
    streamBannerCompletedEyebrow: 'Danke fürs Mitfiebern',
    streamBannerCompletedTitle: 'Award-Show abgeschlossen',
    streamBannerCompletedText: 'Die grosse Award-Show ist vorbei. Danke an alle, die nominiert, gevotet und live mitgefiebert haben.',
    streamBannerCompletedButtonLabel: 'Highlights ansehen',
    streamBannerCompletedButtonUrl: '',
    awardsSectionTitle: '',
    awardsSectionDescription: '',
    subcategoriesSectionTitle: '',
    subcategoriesSectionDescription: '',
    socialLinks: [],
    faq: [],
    showactFormSchemaJson: '[]',
  }
}

export function createEmptyAdminOptionalFeatureSettings(): AdminOptionalFeatureSettingsResponse {
  return {
    clipSubmissionsEnabled: false,
    clipReviewEnabled: true,
    clipAdminMenuVisible: true,
    clipSubmissionDisabledMessage: 'Clip-Einreichungen sind aktuell geschlossen.',
    showactApplicationsEnabled: false,
    showactApplicationStartsAt: null,
    showactApplicationEndsAt: null,
    showactApplicationsOpenNow: false,
    showactApplicationDisabledMessage: 'Showact-Bewerbungen sind aktuell geschlossen.',
    sponsorsVisible: true,
  }
}

export function createEmptyDatabaseHealth(): DatabaseHealthResponse {
  return {
    provider: 'postgres',
    canConnect: false,
    pendingMigrations: [],
    configuredConnection: {
      source: 'unknown',
    },
  }
}

export function createAwardsState() {
  return {
    overview: createEmptyOverview(),
    categories: createEmptyCategories(),
    archive: createEmptyArchive(),
    publicSponsors: createEmptyPublicSponsors(),
    admin: createEmptyAdminDashboard(),
    adminSeasons: [] as AdminSeasonListItem[],
    adminSeasonDetail: createEmptyAdminSeasonDetail(),
    adminSiteSettings: createEmptyAdminSiteSettings(),
    adminOperationalSettings: createEmptyAdminOperationalSettings(),
    adminOptionalFeatureSettings: createEmptyAdminOptionalFeatureSettings(),
    adminWorkflowRules: createEmptyAdminWorkflowRulesResponse(),
    adminTrackingRules: createEmptyAdminTrackingRulesResponse(),
    adminArchivedWinners: [] as AdminArchivedWinnerItem[],
    adminSponsors: [] as AdminSponsorItem[],
    adminShowactApplications: [] as AdminShowactApplicationItem[],
    adminRiskHistory: [] as AdminRiskFlag[],
    adminRiskFlagsPage: createEmptyAdminRiskFlagsResponse(),
    adminRiskHistoryPage: createEmptyAdminRiskFlagsResponse(),
    databaseHealth: createEmptyDatabaseHealth(),
    adminSelectedSeasonId: null as number | null,
    loading: false,
    apiMode: 'fallback' as ApiMode,
    lastPublicError: null as string | null,
    lastPublicErrorKind: null as PublicErrorKind,
  }
}

/**
 * Guarantee the array fields exist even if a (possibly older) backend omits them,
 * so views can safely read `.length`/`.filter` without crashing the render.
 */
export function normalizeSeasonDetail(detail: AdminSeasonDetailResponse): AdminSeasonDetailResponse {
  return {
    ...detail,
    winnersPublishedAt: detail.winnersPublishedAt ?? null,
    winnersPublishedByTwitchId: detail.winnersPublishedByTwitchId ?? null,
    subcategoryTemplates: detail.subcategoryTemplates ?? [],
    categories: detail.categories ?? [],
    candidates: (detail.candidates ?? []).map((candidate) => ({
      ...candidate,
      acceptanceStatus: candidate.acceptanceStatus ?? 'open',
      acceptanceNote: candidate.acceptanceNote ?? null,
      clipCompilationUrl: candidate.clipCompilationUrl ?? null,
      clipCompilationTitle: candidate.clipCompilationTitle ?? null,
      clipCompilationPlatform: candidate.clipCompilationPlatform ?? null,
      clipEmbedStatus: candidate.clipEmbedStatus ?? 'unchecked',
      streamerIdentityId: candidate.streamerIdentityId ?? null,
      avgViewers: candidate.avgViewers ?? null,
      votes: candidate.votes ?? 0,
      nominationTally: candidate.nominationTally ?? 0,
    })),
    pendingNominations: detail.pendingNominations ?? [],
    pendingNominationGroups: detail.pendingNominationGroups ?? [],
    reviewedNominations: detail.reviewedNominations ?? [],
    trackingReviewNotes: detail.trackingReviewNotes ?? '',
    results: detail.results ?? [],
    votingWorkspace: {
      summary: {
        totalVotes: detail.votingWorkspace?.summary?.totalVotes ?? 0,
        totalSubcategories: detail.votingWorkspace?.summary?.totalSubcategories ?? 0,
        votedSubcategories: detail.votingWorkspace?.summary?.votedSubcategories ?? 0,
        readySubcategories: detail.votingWorkspace?.summary?.readySubcategories ?? 0,
        problemSubcategories: detail.votingWorkspace?.summary?.problemSubcategories ?? 0,
        winnerSetSubcategories: detail.votingWorkspace?.summary?.winnerSetSubcategories ?? 0,
      },
      categories: (detail.votingWorkspace?.categories ?? []).map((category) => ({
        ...category,
        leaderboard: category.leaderboard ?? [],
      })),
    },
    clipSubmissions: detail.clipSubmissions ?? [],
  }
}

export function classifyPublicLoadError(error: unknown) {
  const message = error instanceof Error ? error.message : 'Die Landingpage konnte nicht geladen werden.'
  const isOffline = typeof navigator !== 'undefined' && navigator.onLine === false
  const isUnreachable = message.toLowerCase().includes('api nicht erreichbar')
  const isServerError = error instanceof ApiRequestError && error.status !== null && error.status >= 500

  return {
    message,
    kind: isOffline ? 'offline' : isServerError ? 'server' : isUnreachable ? 'unreachable' : null,
  } satisfies { message: string; kind: PublicErrorKind }
}
