import type { Memory, TagColor, SortField, SortDirection, SortOptions } from '../types'

/**
 * Extract tags from a memory object
 */
export function extractTags(memory: Memory): string[] {
  if (memory.tags && Array.isArray(memory.tags)) {
    return memory.tags
  }
  return []
}

/**
 * Generate a color scheme for a tag based on its content
 */
export function getTagColor(tag: string): TagColor {
  let hash = 0
  for (let i = 0; i < tag.length; i++) {
    hash = tag.charCodeAt(i) + ((hash << 5) - hash)
  }
  
  const hue = Math.abs(hash) % 360
  const saturation = 60 + (Math.abs(hash) % 30) // 60-90%
  const lightness = 25 + (Math.abs(hash) % 15)  // 25-40% for dark backgrounds
  
  return {
    bg: `hsl(${hue}, ${saturation}%, ${lightness}%)`,
    text: `hsl(${hue}, ${Math.max(saturation - 10, 50)}%, 85%)`, // Light text for dark bg
    border: `hsl(${hue}, ${saturation}%, ${lightness + 15}%)`
  }
}

/**
 * Extract a meaningful title from memory content
 */
export function extractTitle(content: string, memory?: Memory): string {
  // Check for LLM-generated title first
  if (memory) {
    const tags = extractTags(memory)
    const titleTag = tags.find(tag => tag.startsWith('title:'))
    if (titleTag) {
      return titleTag.substring(6) // Remove 'title:' prefix
    }
  }
  
  // Enhanced title extraction
  const lines = content.split('\\n').filter(line => line.trim())
  
  // Look for markdown headers
  const headerMatch = content.match(/^#{1,6}\\s+(.+)$/m)
  if (headerMatch) {
    return headerMatch[1].trim()
  }
  
  // Look for structured patterns
  const structuredPatterns = [
    /^(.+?):\\s*[\\r\\n]/m,  // "Title: content"
    /^"(.+?)"/m,          // Quoted titles
    /^\\*\\*(.+?)\\*\\*/m,     // Bold markdown
    /^__(.+?)__/m,        // Bold underscore
    /^\\[(.+?)\\]/m,        // Bracketed content
  ]
  
  for (const pattern of structuredPatterns) {
    const match = content.match(pattern)
    if (match && match[1].length < 60 && match[1].length > 5) {
      return match[1].trim()
    }
  }
  
  // Development patterns
  const devPatterns = [
    /(?:Phase|Step|Task)\\s+(\\d+)[:\\s]+(.+?)(?:[\\r\\n]|$)/i,
    /(?:Feature|Bug|Fix)[:\\s]+(.+?)(?:[\\r\\n]|$)/i,
    /(?:TODO|DONE|WIP)[:\\s]+(.+?)(?:[\\r\\n]|$)/i,
    /^\\d+[.)\\s]+(.+?)(?:[\\r\\n]|$)/m, // Numbered lists
  ]
  
  for (const pattern of devPatterns) {
    const match = content.match(pattern)
    if (match) {
      const title = (match[2] || match[1]).trim()
      if (title.length < 60 && title.length > 5) {
        return title
      }
    }
  }
  
  // Extract key phrases from content
  const sentences = content.split(/[.!?\\n]+/).filter(s => s.trim().length > 10)
  for (const sentence of sentences.slice(0, 3)) {
    const cleaned = sentence.trim()
    // Skip generic patterns
    if (!cleaned.match(/^(project location|current|status|update|working|running)/i) &&
        cleaned.length > 15 && cleaned.length < 80) {
      return cleaned
    }
  }
  
  // Use meaningful keywords
  const keywords = content.toLowerCase().match(/\\b(dashboard|api|component|feature|bug|fix|update|implement|create|add)\\b/g)
  if (keywords && keywords.length > 0) {
    const firstSentence = sentences[0]?.trim()
    if (firstSentence && firstSentence.length < 100) {
      return firstSentence
    }
  }
  
  // Fallback to first meaningful sentence
  const fallback = sentences[0]?.trim()
  if (fallback && fallback.length < 100) {
    return fallback
  }
  
  return content.substring(0, 50) + (content.length > 50 ? '...' : '')
}

/**
 * Generate a summary from memory content
 */
export function generateSummary(content: string, memory?: Memory): string {
  // Check for LLM-generated summary first
  if (memory) {
    const tags = extractTags(memory)
    const summaryTag = tags.find(tag => tag.startsWith('summary:'))
    if (summaryTag) {
      return summaryTag.substring(8) // Remove 'summary:' prefix
    }
  }
  
  // Extract first few sentences for summary
  const sentences = content.split(/[.!?\\n]+/).filter(s => s.trim().length > 10)
  const summary = sentences.slice(0, 2).join('. ').trim()
  
  if (summary.length > 0) {
    return summary.length > 200 ? summary.substring(0, 197) + '...' : summary
  }
  
  return content.substring(0, 150) + (content.length > 150 ? '...' : '')
}

/**
 * Format timestamp for display
 */
export function formatTimestamp(timestamp: string | Date): string {
  const date = new Date(timestamp)
  return date.toLocaleString()
}

/**
 * Format date for display
 */
export function formatDate(timestamp: string | Date): string {
  const date = new Date(timestamp)
  return date.toLocaleDateString()
}

/**
 * Calculate days since a timestamp
 */
export function daysSince(timestamp: string | Date): number {
  const date = new Date(timestamp)
  const now = new Date()
  const diffTime = Math.abs(now.getTime() - date.getTime())
  return Math.ceil(diffTime / (1000 * 60 * 60 * 24))
}

/**
 * Format a date string to show relative time (e.g., "2 hours ago")
 */
export function formatDistanceToNow(dateString: string): string {
  const date = new Date(dateString)
  const now = new Date()
  const diffInMs = now.getTime() - date.getTime()
  
  const minute = 60 * 1000
  const hour = minute * 60
  const day = hour * 24
  const week = day * 7
  const month = day * 30
  const year = day * 365
  
  if (diffInMs < minute) {
    return "just now"
  } else if (diffInMs < hour) {
    const minutes = Math.floor(diffInMs / minute)
    return `${minutes} minute${minutes !== 1 ? 's' : ''} ago`
  } else if (diffInMs < day) {
    const hours = Math.floor(diffInMs / hour)
    return `${hours} hour${hours !== 1 ? 's' : ''} ago`
  } else if (diffInMs < week) {
    const days = Math.floor(diffInMs / day)
    return `${days} day${days !== 1 ? 's' : ''} ago`
  } else if (diffInMs < month) {
    const weeks = Math.floor(diffInMs / week)
    return `${weeks} week${weeks !== 1 ? 's' : ''} ago`
  } else if (diffInMs < year) {
    const months = Math.floor(diffInMs / month)
    return `${months} month${months !== 1 ? 's' : ''} ago`
  } else {
    const years = Math.floor(diffInMs / year)
    return `${years} year${years !== 1 ? 's' : ''} ago`
  }
}

/**
 * Truncate text to specified length with ellipsis
 */
export function truncateText(text: string, maxLength: number): string {
  if (text.length <= maxLength) return text
  return text.substring(0, maxLength) + "..."
}

/**
 * Generate a random UUID v4
 */
export function generateUUID(): string {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    const r = Math.random() * 16 | 0
    const v = c == 'x' ? r : (r & 0x3 | 0x8)
    return v.toString(16)
  })
}

/**
 * Calculate content size in bytes
 */
export function calculateContentSize(content: string): number {
  return new Blob([content]).size
}

/**
 * Detect content type based on content
 */
export function detectContentType(content: string): 'text' | 'code' | 'structured' {
  // Check for code patterns
  const codePatterns = [
    /```[\s\S]*```/,  // Code blocks
    /function\s+\w+\s*\(/,  // Function declarations
    /class\s+\w+/,  // Class declarations
    /import\s+.*from/,  // Import statements
    /export\s+(default\s+)?/,  // Export statements
    /<\w+[^>]*>/,  // HTML tags
    /\{\s*"[\w"]+\s*:/  // JSON-like patterns
  ]
  
  if (codePatterns.some(pattern => pattern.test(content))) {
    return 'code'
  }
  
  // Check for structured data
  try {
    JSON.parse(content)
    return 'structured'
  } catch {
    // Not JSON
  }
  
  // Check for YAML-like patterns
  if (/^[\w\-]+:\s*/.test(content) || content.includes('---\n')) {
    return 'structured'
  }
  
  return 'text'
}

/**
 * Search memories with advanced filters
 */
export function searchMemories(memories: Memory[], query: string, filters?: any): Memory[] {
  let results = memories
  
  // Text search
  if (query.trim()) {
    const searchTerm = query.toLowerCase()
    results = results.filter(memory => 
      memory.content.toLowerCase().includes(searchTerm) ||
      (memory.tags && memory.tags.some((tag: string) => tag.toLowerCase().includes(searchTerm))) ||
      (memory.project && memory.project.toLowerCase().includes(searchTerm))
    )
  }
  
  // Apply filters
  if (filters) {
    if (filters.category) {
      results = results.filter(memory => memory.category === filters.category)
    }
    
    if (filters.project) {
      results = results.filter(memory => memory.project === filters.project)
    }
    
    if (filters.tags && filters.tags.length > 0) {
      results = results.filter(memory => 
        memory.tags && filters.tags.some((tag: string) => memory.tags.includes(tag))
      )
    }
    
    if (filters.contentType) {
      results = results.filter(memory => 
        memory.metadata?.contentType === filters.contentType
      )
    }
    
    if (filters.dateRange) {
      const startDate = new Date(filters.dateRange.start)
      const endDate = new Date(filters.dateRange.end)
      results = results.filter(memory => {
        const memoryDate = new Date(memory.metadata?.created || memory.timestamp)
        return memoryDate >= startDate && memoryDate <= endDate
      })
    }
  }
  
  return results
}

/**
 * Sort memories by various criteria with performance optimization
 */
export function sortMemories(memories: Memory[], sortOptions: SortOptions): Memory[] {
  if (!memories.length) return memories
  
  const { field, direction } = sortOptions
  
  return [...memories].sort((a, b) => {
    let comparison = 0
    
    switch (field) {
      case 'date':
        const dateA = new Date(a.metadata?.created || a.timestamp).getTime()
        const dateB = new Date(b.metadata?.created || b.timestamp).getTime()
        comparison = dateA - dateB
        break
        
      case 'title':
        const titleA = extractTitle(a.content, a).toLowerCase()
        const titleB = extractTitle(b.content, b).toLowerCase()
        comparison = titleA.localeCompare(titleB)
        break
        
      case 'length':
        comparison = a.content.length - b.content.length
        break
        
      case 'tags':
        const tagsA = extractTags(a).length
        const tagsB = extractTags(b).length
        comparison = tagsA - tagsB
        break
        
      case 'project':
        const projectA = (a.project || 'default').toLowerCase()
        const projectB = (b.project || 'default').toLowerCase()
        comparison = projectA.localeCompare(projectB)
        break
        
      case 'category':
        const categoryA = (a.category || 'personal').toLowerCase()
        const categoryB = (b.category || 'personal').toLowerCase()
        comparison = categoryA.localeCompare(categoryB)
        break
        
      default:
        return 0
    }
    
    // Apply sort direction
    return direction === 'asc' ? comparison : -comparison
  })
}

/**
 * Get display info for sort fields (used in UI)
 */
export function getSortFieldInfo(field: SortField): { label: string; icon: string; description: string } {
  const sortFieldMap = {
    date: { label: 'Date Created', icon: '📅', description: 'When memory was created' },
    title: { label: 'Title', icon: '📝', description: 'Alphabetical by title' },
    length: { label: 'Content Length', icon: '📏', description: 'By amount of content' },
    tags: { label: 'Tag Count', icon: '🏷️', description: 'By number of tags' },
    project: { label: 'Project', icon: '📁', description: 'Alphabetical by project' },
    category: { label: 'Category', icon: '📂', description: 'By memory category' }
  }
  
  return sortFieldMap[field] || sortFieldMap.date
}