import 'server-only'
import fs from 'fs/promises'
import path from 'path'
import { translateLinkedInPost, enregistrerCacheTraductions } from './translator'

export interface LinkedInPost {
  id: string
  title: string
  titleEn: string
  content: string
  contentEn: string
  date: string
  dateIso: string
  image: string | null
  linkedInUrl: string
  hasMedia: boolean
  mediaType: 'image' | 'video' | 'carousel' | 'none'
}

interface LinkedInConfig {
  clientId: string
  clientSecret: string
  redirectUri: string
  accessToken?: string
  organizationUrn?: string
}

const DATA_FILE = path.join(process.cwd(), 'data', 'linkedin-posts.json')
const IMAGES_DIR = path.join(process.cwd(), 'public', 'media', 'linkedin')
const CONFIG_FILE = path.join(process.cwd(), 'data', 'linkedin-config.json')

// Fonction pour s'assurer que les dossiers existent
async function ensureDirectories() {
  await fs.mkdir(path.dirname(DATA_FILE), { recursive: true })
  await fs.mkdir(IMAGES_DIR, { recursive: true })
}

// Sauvegarde la configuration LinkedIn
export async function saveLinkedInConfig(config: LinkedInConfig) {
  await ensureDirectories()
  await fs.writeFile(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8')
}

/**
 * Charge la configuration LinkedIn, fichier JSON puis variables
 * d'environnement.
 *
 * Le jeton n'est plus exigé pour qu'une configuration soit rendue. Il l'était,
 * et une installation dépourvue de jeton — le cas juste après une expiration —
 * ne rendait rien du tout : l'appelant annonçait alors « fichier de
 * configuration introuvable » pour un fichier bien présent, et l'on cherchait
 * un fichier au lieu de renouveler une autorisation. C'est à l'appelant de
 * dire ce qui manque, il sait le distinguer.
 */
export async function loadLinkedInConfig(): Promise<LinkedInConfig | null> {
  // 1. Le fichier de configuration, écrit par scripts/setup-linkedin.js.
  try {
    const data = await fs.readFile(CONFIG_FILE, 'utf-8')
    const config = JSON.parse(data)
    if (config.clientId && config.organizationUrn) {
      return config
    }
  } catch {
    // fichier absent ou illisible : on tente l'environnement
  }

  // 2. Les variables d'environnement.
  const clientId = process.env.LINKEDIN_CLIENT_ID
  const clientSecret = process.env.LINKEDIN_CLIENT_SECRET
  const accessToken = process.env.LINKEDIN_ACCESS_TOKEN
  const organizationUrn =
    process.env.LINKEDIN_ORG_URN || process.env.LINKEDIN_ORGANIZATION_URN

  if (clientId && organizationUrn) {
    return {
      clientId,
      clientSecret: clientSecret || '',
      redirectUri: process.env.LINKEDIN_REDIRECT_URI || '',
      accessToken,
      organizationUrn,
    }
  }

  return null
}

// Télécharge une image depuis une URL (avec token optionnel pour les CDN LinkedIn)
async function downloadImage(url: string, filename: string, accessToken?: string): Promise<string | null> {
  try {
    const headers: Record<string, string> = {}
    if (accessToken && url.includes('media.licdn.com')) {
      headers['Authorization'] = `Bearer ${accessToken}`
    }

    const response = await fetch(url, { headers })
    if (!response.ok) {
      console.warn(`[downloadImage] Échec téléchargement (${response.status}) pour: ${url}`)
      return null
    }

    const buffer = await response.arrayBuffer()
    const filepath = path.join(IMAGES_DIR, filename)
    await fs.writeFile(filepath, Buffer.from(buffer))
    console.log(`[downloadImage] Image sauvegardée: ${filename}`)

    return `/media/linkedin/${filename}`
  } catch (error) {
    console.error('Erreur téléchargement image:', error)
    return null
  }
}

// Extrait l'URL de l'image d'un post (uniquement pour les images uniques)
function extractImageFromPost(post: any): string | null {
  try {
    const specificContent = post.specificContent || {}
    const shareContent = specificContent['com.linkedin.ugc.ShareContent'] || {}
    const media = shareContent.media || []
    
    // Vérifie qu'il y a exactement 1 média (image unique)
    if (media.length === 1) {
      const mediaItem = media[0]
      
      // Vérifie que ce n'est pas une vidéo
      if (mediaItem.status === 'READY') {
        const thumbnails = mediaItem.thumbnails || []
        if (thumbnails.length > 0) {
          return thumbnails[thumbnails.length - 1].url
        }
        
        if (mediaItem.originalUrl) {
          return mediaItem.originalUrl
        }
      }
    }
    
    return null
  } catch {
    return null
  }
}

// Détermine le type de média d'un post
function getMediaType(post: any): 'image' | 'video' | 'carousel' | 'none' {
  try {
    const specificContent = post.specificContent || {}
    const shareContent = specificContent['com.linkedin.ugc.ShareContent'] || {}
    const media = shareContent.media || []
    
    if (media.length === 0) return 'none'
    if (media.length > 1) return 'carousel'
    
    const mediaItem = media[0]
    if (mediaItem.media && mediaItem.media.includes('video')) return 'video'
    
    return 'image'
  } catch {
    return 'none'
  }
}

// Récupère les posts de l'entreprise depuis LinkedIn
export async function fetchLinkedInPosts(accessToken: string, orgUrn: string): Promise<LinkedInPost[]> {
  try {
    await ensureDirectories()
    
    const encodedUrn = encodeURIComponent(orgUrn)
    const allPosts: any[] = []
    let start = 0
    const count = 100 // LinkedIn permet jusqu'à 100 posts par requête
    let hasMore = true
    
    console.log('📥 Récupération de tous les posts LinkedIn avec pagination...')
    
    // Récupérer tous les posts avec pagination
    while (hasMore) {
      const url = `https://api.linkedin.com/v2/ugcPosts?q=authors&authors=List(${encodedUrn})&sortBy=LAST_MODIFIED&start=${start}&count=${count}`
      
      console.log(`   Requête page ${Math.floor(start / count) + 1} (posts ${start} à ${start + count})...`)
      
      const response = await fetch(url, {
        headers: {
          'Authorization': `Bearer ${accessToken}`,
          'X-Restli-Protocol-Version': '2.0.0'
        }
      })
      
      if (!response.ok) {
        throw new Error(`Erreur API LinkedIn: ${response.status}`)
      }
      
      const data = await response.json()
      const posts = data.elements || []
      
      if (posts.length === 0) {
        hasMore = false
        console.log('   ✅ Tous les posts récupérés!')
      } else {
        allPosts.push(...posts)
        console.log(`   ✓ ${posts.length} posts récupérés (total: ${allPosts.length})`)
        start += count
        
        // Si on reçoit moins que le count demandé, c'est la dernière page
        if (posts.length < count) {
          hasMore = false
          console.log('   ✅ Dernière page atteinte!')
        }
      }
    }
    
    console.log(`\n📊 Total: ${allPosts.length} posts à traiter\n`)
    
    const processedPosts: LinkedInPost[] = []
    
    console.log('🔄 Traitement et traduction des posts en anglais...\n')
    
    for (let idx = 0; idx < allPosts.length; idx++) {
      const post = allPosts[idx]
      
      // Afficher la progression tous les 10 posts
      if ((idx + 1) % 10 === 0) {
        console.log(`   Traité et traduit ${idx + 1}/${allPosts.length} posts...`)
      }
      
      try {
        const shareContent = post.specificContent?.['com.linkedin.ugc.ShareContent']
        const text = shareContent?.shareCommentary?.text || ''
        const postId = post.id
        const postUrl = `https://www.linkedin.com/feed/update/${postId}`
        const createdTime = post.created?.time || Date.now()
        const date = new Date(createdTime)
        
        const mediaType = getMediaType(post)
        const hasMedia = mediaType !== 'none'
        
        let imagePath: string | null = null
        
        // Si c'est une image unique, on la télécharge
        if (mediaType === 'image') {
          const imageUrl = extractImageFromPost(post)
          if (imageUrl) {
            console.log(`[fetchLinkedInPosts] Image trouvée pour post ${idx + 1}: ${imageUrl.substring(0, 80)}...`)
            const filename = `post_${postId.replace(/[^a-zA-Z0-9]/g, '_')}_${Date.now()}.jpg`
            imagePath = await downloadImage(imageUrl, filename, accessToken)
          } else {
            console.log(`[fetchLinkedInPosts] Aucune URL image extraite pour post ${idx + 1} (type: ${mediaType})`)
          }
        }
        
        // Si pas d'image ou média autre, utiliser l'image générique
        if (!imagePath && hasMedia) {
          imagePath = '/media/generique.jpg'
        }
        
        // Extraire un titre (premières lignes du texte), vide si pas de texte
        const lines = text.split('\n').filter((l: string) => l.trim())
        const title = lines[0]?.substring(0, 100) || ''

        // Traduction automatique en anglais (si activée)
        let titleEn = title
        let contentEn = text
        
        if (process.env.ENABLE_AUTO_TRANSLATION === 'true') {
          const translation = await translateLinkedInPost(title, text)
          titleEn = translation.titleEn
          contentEn = translation.contentEn
        }
        
        processedPosts.push({
          id: postId,
          title,
          titleEn,
          content: text,
          contentEn,
          date: date.toLocaleDateString('fr-FR'),
          dateIso: date.toISOString(),
          image: imagePath,
          linkedInUrl: postUrl,
          hasMedia,
          mediaType
        })
      } catch (error) {
        console.error(`Erreur traitement post ${idx}:`, error)
        continue
      }
    }
    
    // Sauvegarde les posts dans le fichier JSON
    await fs.writeFile(DATA_FILE, JSON.stringify(processedPosts, null, 2), 'utf-8')

    // Le cache de traduction est écrit une fois la moisson terminée : une
    // écriture par publication multiplierait les accès disque pour un fichier
    // qui ne sert qu'à la synchronisation suivante.
    await enregistrerCacheTraductions()

    console.log(`\n✅ ${processedPosts.length} posts LinkedIn synchronisés et sauvegardés!`)
    
    return processedPosts
  } catch (error) {
    console.error('Erreur récupération posts LinkedIn:', error)
    throw error
  }
}

// Charge les posts depuis le fichier local
export async function loadLinkedInPosts(): Promise<LinkedInPost[]> {
  try {
    const data = await fs.readFile(DATA_FILE, 'utf-8')
    return JSON.parse(data)
  } catch {
    return []
  }
}

// Synchronise les posts avec le backend Laravel
async function syncToLaravelBackend(posts: LinkedInPost[]): Promise<void> {
  try {
    const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://10.113.245.13:8000'
    
    console.log('\n📤 Envoi des posts au backend Laravel...')
    console.log(`   URL: ${apiUrl}/api/actualites/sync-linkedin`)
    
    const response = await fetch(`${apiUrl}/api/actualites/sync-linkedin`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
      },
      body: JSON.stringify({ posts })
    })
    
    if (!response.ok) {
      const errorText = await response.text()
      throw new Error(`Erreur backend (${response.status}): ${errorText}`)
    }
    
    const result = await response.json()
    
    console.log(`\n✅ Synchronisation Laravel réussie!`)
    console.log(`   📊 Créés: ${result.stats?.created || 0}`)
    console.log(`   📝 Mis à jour: ${result.stats?.updated || 0}`)
    console.log(`   ⚠️  Erreurs: ${result.stats?.errors || 0}`)
    
    if (result.errors && result.errors.length > 0) {
      console.log('\n⚠️  Détails des erreurs:')
      result.errors.forEach((err: any) => {
        console.log(`   - ${err.post}: ${err.error}`)
      })
    }
  } catch (error) {
    console.error('\n❌ Erreur synchronisation Laravel:', error instanceof Error ? error.message : error)
    throw error
  }
}

// Synchronise les posts LinkedIn (appelé par le cron job)
export async function syncLinkedInPosts(): Promise<{ success: boolean; count: number; error?: string }> {
  try {
    console.log('[syncLinkedInPosts] Chargement de la configuration...')
    const config = await loadLinkedInConfig()

    console.log('[syncLinkedInPosts] Config chargée:', {
      hasConfig: !!config,
      hasAccessToken: !!config?.accessToken,
      hasOrganizationUrn: !!config?.organizationUrn,
      clientId: config?.clientId || '(vide)',
    })

    if (!config) {
      return { success: false, count: 0, error: 'Fichier de configuration LinkedIn introuvable (data/linkedin-config.json)' }
    }
    if (!config.accessToken) {
      return {
        success: false,
        count: 0,
        error:
          "Aucun jeton d'accès LinkedIn. L'autorisation est à refaire : "
          + 'node scripts/setup-linkedin.js',
      }
    }
    if (!config.organizationUrn) {
      return { success: false, count: 0, error: 'Organization URN LinkedIn manquant dans la configuration' }
    }

    console.log('[syncLinkedInPosts] Récupération des posts LinkedIn...')
    const posts = await fetchLinkedInPosts(config.accessToken, config.organizationUrn)
    console.log(`[syncLinkedInPosts] ${posts.length} posts récupérés`)

    // Synchroniser avec le backend Laravel
    try {
      await syncToLaravelBackend(posts)
    } catch (error) {
      console.warn('⚠️  Échec de la synchronisation Laravel, mais les posts sont sauvegardés localement')
      console.warn('   Erreur:', error instanceof Error ? error.message : error)
    }

    return {
      success: true,
      count: posts.length
    }
  } catch (error) {
    console.error('[syncLinkedInPosts] Exception:', error)
    return {
      success: false,
      count: 0,
      error: error instanceof Error ? error.message : 'Erreur inconnue'
    }
  }
}
