import axios from 'axios'
import type { Channel } from '../../shared/types'
import { randomUUID } from 'crypto'

interface M3u8Entry {
  name: string
  url: string
  group?: string
  logo?: string
  tvgId?: string
  tvgName?: string
}

export class M3u8Parser {
  /**
   * Parse M3U8/M3U playlist from URL
   */
  async parse(url: string): Promise<Channel[]> {
    try {
      const response = await axios.get(url, {
        timeout: 30000,
        headers: {
          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        },
        responseType: 'text'
      })

      const content = response.data as string
      return this.parseContent(content)
    } catch (error) {
      console.error('Failed to fetch M3U8:', error)
      throw new Error(`Failed to fetch playlist: ${(error as Error).message}`)
    }
  }

  /**
   * Parse M3U8/M3U content string
   */
  parseContent(content: string): Channel[] {
    const lines = content.split('\n').map(line => line.trim())
    const entries: M3u8Entry[] = []
    
    let currentEntry: Partial<M3u8Entry> | null = null

    for (let i = 0; i < lines.length; i++) {
      const line = lines[i]

      // Skip empty lines and M3U header
      if (!line || line === '#EXTM3U') continue

      // Parse EXTINF line
      if (line.startsWith('#EXTINF:')) {
        currentEntry = this.parseExtInf(line)
        continue
      }

      // Parse additional attributes
      if (line.startsWith('#EXTGRP:') && currentEntry) {
        currentEntry.group = line.replace('#EXTGRP:', '').trim()
        continue
      }

      // Skip other comments
      if (line.startsWith('#')) continue

      // This should be a URL
      if (currentEntry && this.isValidUrl(line)) {
        currentEntry.url = line
        entries.push(currentEntry as M3u8Entry)
        currentEntry = null
      } else if (this.isValidUrl(line)) {
        // URL without EXTINF
        entries.push({
          name: this.extractNameFromUrl(line),
          url: line
        })
      }
    }

    return entries.map(entry => this.entryToChannel(entry))
  }

  /**
   * Parse #EXTINF line and extract metadata
   */
  private parseExtInf(line: string): Partial<M3u8Entry> {
    const entry: Partial<M3u8Entry> = {}
    
    // Remove #EXTINF: prefix
    let content = line.replace('#EXTINF:', '')
    
    // Extract duration (usually -1 for live streams)
    const durationMatch = content.match(/^-?\d+/)
    if (durationMatch) {
      content = content.substring(durationMatch[0].length)
    }

    // Parse attributes in format: key="value"
    const attrRegex = /(\w+(?:-\w+)*)=["']([^"']*)["']/g
    let match

    while ((match = attrRegex.exec(content)) !== null) {
      const [, key, value] = match
      
      switch (key.toLowerCase()) {
        case 'tvg-id':
          entry.tvgId = value
          break
        case 'tvg-name':
          entry.tvgName = value
          break
        case 'tvg-logo':
        case 'logo':
          entry.logo = value
          break
        case 'group-title':
          entry.group = value
          break
      }
    }

    // Extract channel name (after last comma)
    const nameMatch = content.match(/,(.+)$/)
    if (nameMatch) {
      entry.name = nameMatch[1].trim()
    } else {
      // Try to use tvg-name if no name after comma
      entry.name = entry.tvgName || 'Unknown Channel'
    }

    return entry
  }

  /**
   * Convert M3U entry to Channel object
   */
  private entryToChannel(entry: M3u8Entry): Channel {
    return {
      id: randomUUID(),
      name: entry.name,
      url: entry.url,
      group: entry.group,
      logo: entry.logo,
      isMonitored: false,
      status: 'unknown'
    }
  }

  /**
   * Check if string is a valid URL
   */
  private isValidUrl(str: string): boolean {
    try {
      new URL(str)
      return true
    } catch {
      return false
    }
  }

  /**
   * Extract channel name from URL
   */
  private extractNameFromUrl(url: string): string {
    try {
      const parsed = new URL(url)
      const pathParts = parsed.pathname.split('/')
      const lastPart = pathParts[pathParts.length - 1] || pathParts[pathParts.length - 2]
      
      // Remove file extension
      const name = lastPart.replace(/\.(m3u8?|ts|mp4)$/i, '')
      
      // Clean up the name
      return name
        .replace(/[_-]/g, ' ')
        .replace(/\s+/g, ' ')
        .trim() || parsed.hostname
    } catch {
      return 'Unknown Channel'
    }
  }

  /**
   * Get unique groups from channels
   */
  static getGroups(channels: Channel[]): string[] {
    const groups = new Set<string>()
    channels.forEach(channel => {
      if (channel.group) {
        groups.add(channel.group)
      }
    })
    return Array.from(groups).sort()
  }
}

