import { reactive } from 'vue'
import { BaseService } from '@/core/base/BaseService'
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
import type { Event as NostrEvent, Filter } from 'nostr-tools'

export interface UserProfile {
  pubkey: string
  name?: string
  display_name?: string
  about?: string
  picture?: string
  nip05?: string
  updated_at: number
}

export class ProfileService extends BaseService {
  protected readonly metadata = {
    name: 'ProfileService',
    version: '1.0.0',
    dependencies: []
  }

  protected relayHub: any = null

  // Profile cache - reactive for UI updates
  private _profiles = reactive(new Map<string, UserProfile>())
  private currentSubscription: string | null = null
  private currentUnsubscribe: (() => void) | null = null

  // Track which profiles we've requested to avoid duplicate requests
  private requestedProfiles = new Set<string>()

  protected async onInitialize(): Promise<void> {
    console.log('ProfileService: Starting initialization...')

    this.relayHub = injectService(SERVICE_TOKENS.RELAY_HUB)

    if (!this.relayHub) {
      throw new Error('RelayHub service not available')
    }

    console.log('ProfileService: Initialization complete')
  }

  /**
   * Get profile for a pubkey, fetching if not cached
   */
  async getProfile(pubkey: string): Promise<UserProfile | null> {
    // Return cached profile if available
    if (this._profiles.has(pubkey)) {
      return this._profiles.get(pubkey)!
    }

    // If not requested yet, fetch it
    if (!this.requestedProfiles.has(pubkey)) {
      await this.fetchProfile(pubkey)
    }

    return this._profiles.get(pubkey) || null
  }

  /**
   * Get display name for a pubkey (returns formatted pubkey if no profile)
   */
  getDisplayName(pubkey: string): string {
    const profile = this._profiles.get(pubkey)
    if (profile?.display_name) return profile.display_name
    if (profile?.name) return profile.name

    // Return formatted pubkey as fallback
    return `${pubkey.slice(0, 8)}...${pubkey.slice(-4)}`
  }

  /**
   * Fetch profile for specific pubkey
   */
  private async fetchProfile(pubkey: string): Promise<void> {
    if (!this.relayHub || this.requestedProfiles.has(pubkey)) {
      return
    }

    this.requestedProfiles.add(pubkey)

    try {
      if (!this.relayHub.isConnected) {
        await this.relayHub.connect()
      }

      const subscriptionId = `profile-${pubkey}-${Date.now()}`

      const filter: Filter = {
        kinds: [0], // Profile metadata
        authors: [pubkey],
        limit: 1
      }

      console.log(`ProfileService: Fetching profile for ${pubkey.slice(0, 8)}...`)

      const unsubscribe = this.relayHub.subscribe({
        id: subscriptionId,
        filters: [filter],
        onEvent: (event: NostrEvent) => {
          this.handleProfileEvent(event)
        },
        onEose: () => {
          console.log(`Profile subscription ${subscriptionId} complete`)
          // Clean up subscription after getting the profile
          if (unsubscribe) {
            unsubscribe()
          }
        }
      })

    } catch (error) {
      console.error(`Failed to fetch profile for ${pubkey}:`, error)
      this.requestedProfiles.delete(pubkey) // Allow retry
    }
  }

  /**
   * Handle incoming profile event
   */
  private handleProfileEvent(event: NostrEvent): void {
    try {
      const metadata = JSON.parse(event.content)

      const profile: UserProfile = {
        pubkey: event.pubkey,
        name: metadata.name,
        display_name: metadata.display_name,
        about: metadata.about,
        picture: metadata.picture,
        nip05: metadata.nip05,
        updated_at: event.created_at
      }

      // Only update if this is newer than what we have
      const existing = this._profiles.get(event.pubkey)
      if (!existing || event.created_at > existing.updated_at) {
        this._profiles.set(event.pubkey, profile)
        console.log(`ProfileService: Updated profile for ${event.pubkey.slice(0, 8)}...`, profile.display_name || profile.name)
      }

    } catch (error) {
      console.error('Failed to parse profile metadata:', error)
    }
  }

  /**
   * Bulk fetch profiles for multiple pubkeys
   */
  async fetchProfiles(pubkeys: string[]): Promise<void> {
    const unfetchedPubkeys = pubkeys.filter(pubkey =>
      !this._profiles.has(pubkey) && !this.requestedProfiles.has(pubkey)
    )

    if (unfetchedPubkeys.length === 0) return

    console.log(`ProfileService: Bulk fetching ${unfetchedPubkeys.length} profiles`)

    try {
      if (!this.relayHub?.isConnected) {
        await this.relayHub?.connect()
      }

      const subscriptionId = `profiles-bulk-${Date.now()}`

      // Mark all as requested
      unfetchedPubkeys.forEach(pubkey => this.requestedProfiles.add(pubkey))

      const filter: Filter = {
        kinds: [0],
        authors: unfetchedPubkeys,
        limit: unfetchedPubkeys.length
      }

      const unsubscribe = this.relayHub.subscribe({
        id: subscriptionId,
        filters: [filter],
        onEvent: (event: NostrEvent) => {
          this.handleProfileEvent(event)
        },
        onEose: () => {
          console.log(`Bulk profile subscription ${subscriptionId} complete`)
          if (unsubscribe) {
            unsubscribe()
          }
        }
      })

    } catch (error) {
      console.error('Failed to bulk fetch profiles:', error)
      // Remove from requested so they can be retried
      unfetchedPubkeys.forEach(pubkey => this.requestedProfiles.delete(pubkey))
    }
  }

  /**
   * Subscribe to real-time profile updates for active users
   */
  async subscribeToProfileUpdates(pubkeys: string[]): Promise<void> {
    if (this.currentSubscription) {
      await this.unsubscribeFromProfiles()
    }

    if (pubkeys.length === 0) return

    try {
      if (!this.relayHub?.isConnected) {
        await this.relayHub?.connect()
      }

      const subscriptionId = `profile-updates-${Date.now()}`

      const filter: Filter = {
        kinds: [0],
        authors: pubkeys
      }

      console.log(`ProfileService: Subscribing to profile updates for ${pubkeys.length} users`)

      const unsubscribe = this.relayHub.subscribe({
        id: subscriptionId,
        filters: [filter],
        onEvent: (event: NostrEvent) => {
          this.handleProfileEvent(event)
        },
        onEose: () => {
          console.log(`Profile updates subscription ${subscriptionId} ready`)
        }
      })

      this.currentSubscription = subscriptionId
      this.currentUnsubscribe = unsubscribe

    } catch (error) {
      console.error('Failed to subscribe to profile updates:', error)
    }
  }

  /**
   * Unsubscribe from profile updates
   */
  async unsubscribeFromProfiles(): Promise<void> {
    if (this.currentUnsubscribe) {
      this.currentUnsubscribe()
      this.currentSubscription = null
      this.currentUnsubscribe = null
    }
  }

  /**
   * Clear profile cache
   */
  clearCache(): void {
    this._profiles.clear()
    this.requestedProfiles.clear()
  }

  /**
   * Get all cached profiles
   */
  get profiles(): Map<string, UserProfile> {
    return this._profiles
  }

  /**
   * Cleanup
   */
  protected async onDestroy(): Promise<void> {
    await this.unsubscribeFromProfiles()
    this.clearCache()
  }
}