import _ from 'lodash'
import { NDKEvent } from '@nostr-dev-kit/ndk'
import { Event } from 'nostr-tools'
import { ModDetails, ModFormState } from '../types'
import { getTagValue, getTagValues, getFirstTagValue as _getFirstTagValue } from './nostr'

/**
 * Extracts and normalizes mod data from an event.
 *
 * This function extracts specific tag values from an event and maps them to properties
 * of a `PageData` object. It handles default values and type conversions as needed.
 *
 * @param event - The event object from which to extract data.
 * @returns A `Partial<PageData>` object containing extracted data.
 */
export const extractModData = (event: Event | NDKEvent): ModDetails => {
  // Helper function to safely get the first value of a tag or return a default value
  const getFirstTagValue = (tagIdentifier: string, defaultValue = '') => {
    const tagValue = getTagValue(event, tagIdentifier)
    return tagValue ? tagValue[0] : defaultValue
  }

  // Helper function to safely parse integer values from tags
  const getIntTagValue = (tagIdentifier: string, defaultValue: number = -1) => {
    const tagValue = getTagValue(event, tagIdentifier)
    return tagValue ? parseInt(tagValue[0], 10) : defaultValue
  }

  // Optional mod values
  const otherAssets = _getFirstTagValue(event, 'otherAssets')
  const uploadPermission = _getFirstTagValue(event, 'uploadPermission')
  const modPermission = _getFirstTagValue(event, 'modPermission')
  const convPermission = _getFirstTagValue(event, 'convPermission')
  const assetUsePermission = _getFirstTagValue(event, 'assetUsePermission')
  const assetUseComPermission = _getFirstTagValue(event, 'assetUseComPermission')

  return {
    id: event.id,
    dTag: getFirstTagValue('d'),
    aTag: getFirstTagValue('a'),
    rTag: getFirstTagValue('r'),
    author: event.pubkey,
    edited_at: event.created_at!,
    body: event.content,
    published_at: getIntTagValue('published_at'),
    game: getFirstTagValue('game'),
    title: getFirstTagValue('title'),
    featuredImageUrl: getFirstTagValue('featuredImageUrl'),
    summary: getFirstTagValue('summary'),
    nsfw: getFirstTagValue('nsfw') === 'true',
    repost: getFirstTagValue('repost') === 'true',
    originalAuthor: getFirstTagValue('originalAuthor'),
    screenshotsUrls: getTagValue(event, 'screenshotsUrls') || [],
    tags: getTagValue(event, 'tags') || [],
    LTags: (getTagValues(event, 'L') || []).map((t) =>
      t.replace('com.degmods:', '')
    ),
    lTags: (getTagValues(event, 'l') || []).map((t) =>
      t.replace('com.degmods:', '')
    ),
    downloadUrls: (getTagValue(event, 'downloadUrls') || []).map((item) =>
      JSON.parse(item)
    ),
    otherAssets: otherAssets ? otherAssets === 'true' : undefined,
    uploadPermission: uploadPermission ? uploadPermission === 'true' : undefined,
    modPermission: modPermission ? modPermission === 'true' : undefined,
    convPermission: convPermission ? convPermission === 'true' : undefined,
    assetUsePermission: assetUsePermission ? assetUsePermission === 'true' : undefined,
    assetUseComPermission: assetUseComPermission ? assetUseComPermission === 'true' : undefined,
    publisherNotes: _getFirstTagValue(event, 'publisherNotes'),
    extraCredits: _getFirstTagValue(event, 'extraCredits')
  }
}

/**
 * Constructs a list of `ModDetails` objects from an array of events.
 *
 * This function filters out events that do not contain all required data,
 * extracts the necessary information from the valid events, and constructs
 * `ModDetails` objects.
 *
 * @param events - The array of event objects to be processed.
 * @returns An array of `ModDetails` objects constructed from valid events.
 */
export const constructModListFromEvents = (
  events: Event[] | NDKEvent[]
): ModDetails[] => {
  // Filter and extract mod details from events
  const modDetailsList: ModDetails[] = events
    .filter(isModDataComplete) // Filter out incomplete events
    .map((event) => extractModData(event)) // Extract data and construct ModDetails

  return modDetailsList
}

/**
 * Checks if the provided event contains all the required data for constructing a `ModDetails` object.
 *
 * This function verifies that the event has the necessary tags and values to construct a `ModDetails` object.
 *
 * @param event - The event object to be checked.
 * @returns `true` if the event contains all required data; `false` otherwise.
 */
export const isModDataComplete = (event: Event | NDKEvent): boolean => {
  // Helper function to check if a tag value is present and not empty
  const hasTagValue = (tagIdentifier: string): boolean => {
    const value = getTagValue(event, tagIdentifier)
    return !!value && value.length > 0 && value[0].trim() !== ''
  }

  // Check if all required fields are present
  return (
    hasTagValue('d') &&
    hasTagValue('a') &&
    hasTagValue('t') &&
    hasTagValue('published_at') &&
    hasTagValue('game') &&
    hasTagValue('title') &&
    hasTagValue('featuredImageUrl') &&
    hasTagValue('summary') &&
    hasTagValue('nsfw') &&
    getTagValue(event, 'screenshotsUrls') !== null &&
    getTagValue(event, 'tags') !== null &&
    getTagValue(event, 'downloadUrls') !== null
  )
}

/**
 * Initializes the form state with values from existing mod data or defaults.
 *
 * @param existingModData - An optional object containing existing mod details. If provided, its values will be used to populate the form state.
 * @returns The initial state for the form, with values from existingModData if available, otherwise default values.
 */
export const initializeFormState = (
  existingModData?: ModDetails
): ModFormState => ({
  dTag: existingModData?.dTag || '',
  aTag: existingModData?.aTag || '',
  published_at: existingModData?.published_at || 0,
  rTag: existingModData?.rTag || window.location.host,
  game: existingModData?.game || '',
  title: existingModData?.title || '',
  body: existingModData?.body || '',
  featuredImageUrl: existingModData?.featuredImageUrl || '',
  summary: existingModData?.summary || '',
  nsfw: existingModData?.nsfw || false,
  repost: existingModData?.repost || false,
  originalAuthor: existingModData?.originalAuthor || undefined,
  screenshotsUrls: existingModData?.screenshotsUrls || [''],
  tags: existingModData?.tags.join(',') || '',
  lTags: existingModData ? _.clone(existingModData.lTags) : [],
  LTags: existingModData ? _.clone(existingModData.lTags) : [],
  downloadUrls: existingModData
    ? _.cloneDeep(existingModData.downloadUrls)
    : [
        {
          title: '',
          url: '',
          hash: '',
          signatureKey: '',
          malwareScanLink: '',
          modVersion: '',
          customNote: '',
          mediaUrl: ''
        }
      ],
  otherAssets: existingModData?.otherAssets ?? true,
  uploadPermission: existingModData?.uploadPermission ?? true,
  modPermission: existingModData?.modPermission ?? true,
  convPermission:existingModData?.convPermission ?? true,
  assetUsePermission:existingModData?.assetUsePermission ?? true,
  assetUseComPermission:existingModData?.assetUseComPermission ?? false,
  publisherNotes:existingModData?.publisherNotes || '',
  extraCredits:existingModData?.extraCredits || ''
})

export const MOD_DRAFT_CACHE_KEY = 'draft-mod'
