import {useMemo} from 'react'
import {
  type AppBskyAgeassuranceDefs,
  getAgeAssuranceRegionConfig,
  type ModerationPrefs,
} from '@atproto/api'

import {getAge} from '#/lib/strings/time'
import {DEFAULT_LOGGED_OUT_LABEL_PREFERENCES} from '#/state/queries/preferences/const'
import {FALLBACK_REGION_CONFIG} from '#/ageAssurance/const'
import {useAgeAssuranceServerDataContext} from '#/ageAssurance/data'
import {
  type AgeAssuranceFlags,
  type AgeAssuranceMetadata,
  type AgeAssuranceState,
} from '#/ageAssurance/types'
import {type Geolocation, useGeolocation} from '#/geolocation'

/**
 * Get age assurance region config based on geolocation, with fallback to
 * app defaults if no region config is found.
 *
 * See {@link getAgeAssuranceRegionConfig} for the generic option, which can
 * return undefined if the geolocation does not match any AA region.
 */
export function getAgeAssuranceRegionConfigWithFallback(
  config: AppBskyAgeassuranceDefs.Config,
  geolocation: Geolocation,
): AppBskyAgeassuranceDefs.ConfigRegion {
  const region = getAgeAssuranceRegionConfig(config, {
    countryCode: geolocation.countryCode ?? '',
    regionCode: geolocation.regionCode,
  })

  return region || FALLBACK_REGION_CONFIG
}

/**
 * Hook to get the age assurance region config based on current geolocation.
 * Does not fall-back to our app defaults. If no config is found, returns
 * undefined, which indicates no regional age assurance rules apply.
 */
export function useAgeAssuranceRegionConfig() {
  const geolocation = useGeolocation()
  const {config} = useAgeAssuranceServerDataContext()
  return useMemo(() => {
    if (!config) return
    // use generic helper, we want to potentially return undefined
    return getAgeAssuranceRegionConfig(config, {
      countryCode: geolocation.countryCode ?? '',
      regionCode: geolocation.regionCode,
    })
  }, [config, geolocation])
}

/**
 * Hook to get the age assurance region config based on current geolocation.
 * Falls back to our app defaults if no region config is found.
 */
export function useAgeAssuranceRegionConfigWithFallback() {
  return useAgeAssuranceRegionConfig() || FALLBACK_REGION_CONFIG
}

/**
 * Some users may have erroneously set their birth date to the current date
 * if one wasn't set on their account. We previously didn't do validation on
 * the bday dialog, and it defaulted to the current date. This bug _has_ been
 * seen in production, so we need to check for it where possible.
 */
export function isLegacyBirthdateBug(birthDate: string) {
  return ['2025', '2024', '2023'].includes((birthDate || '').slice(0, 4))
}

/**
 * Returns whether the date (converted to an age as a whole integer) is under
 * the provided minimum age.
 */
export function isUnderAge(birthDate: string, age: number) {
  return getAge(new Date(birthDate)) < age
}

export function getBirthdateStringFromAge(age: number) {
  const today = new Date()
  return new Date(
    today.getFullYear() - age,
    today.getMonth(),
    today.getDate() - 1, // set to day before to ensure age is reached
  ).toISOString()
}

export const makeAgeRestrictedModerationPrefs = (
  prefs: ModerationPrefs,
): ModerationPrefs => ({
  ...prefs,
  adultContentEnabled: false,
  labels: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES,
})

export function computeAgeAssuranceFlags({
  _state,
  _regionConfig,
  _metadata,
}: {
  _state: AgeAssuranceState
  _regionConfig: AppBskyAgeassuranceDefs.ConfigRegion
  _metadata?: AgeAssuranceMetadata
}): AgeAssuranceFlags {
  // Don't baby the user. See commit 09e0dff3
  return {
    isAgeRestricted: false,
    adultContentDisabled: false,
    chatDisabled: false,
    groupChatDisabled: false,
    isDeclaredUnderAdultAge: false,
    isOverRegionMinAccessAge: true,
    isOverAppMinAccessAge: true,
  }
}
