/**
 * AI Blog Generator Service
 *
 * Generates SEO-optimized blog posts and social media adaptations using Gemini AI.
 * Supports both Arabic and English content generation.
 *
 * Features:
 * - Blog post generation with SEO optimization
 * - Social media adaptation for multiple platforms
 * - Cover image prompt generation
 * - Generation logging to database
 */

import { GoogleGenAI } from '@google/genai';
import { createId } from '@paralleldrive/cuid2';
import { prisma } from '@/lib/db';
import { logger } from '@/lib/logger';
import {
  type BlogGenerationInput,
  type BlogGenerationOutput,
  type SocialPost,
  type SocialAdaptation,
  type SocialPlatform,
  PLATFORM_LIMITS,
} from '@/lib/types/social-media.types';

const scopedLogger = logger.scope('AIBlogGeneratorService');

// Initialize Gemini client
let geminiClient: GoogleGenAI | null = null;

function getGeminiClient(): GoogleGenAI {
  if (!geminiClient) {
    const apiKey = process.env.GOOGLE_API_KEY;
    if (!apiKey) {
      throw new Error('GOOGLE_API_KEY environment variable is not set');
    }
    geminiClient = new GoogleGenAI({ apiKey });
  }
  return geminiClient;
}

// Model for content generation
const CONTENT_MODEL = process.env.GEMINI_CONTENT_MODEL || 'gemini-2.0-flash';

/**
 * Generate a URL-friendly slug from a title
 */
function generateSlug(title: string, language: 'ar' | 'en'): string {
  if (language === 'ar') {
    // For Arabic, use a timestamp-based slug with transliterated prefix
    return `blog-${Date.now()}-${createId().slice(0, 8)}`;
  }

  return title
    .toLowerCase()
    .trim()
    .replace(/[^\w\s-]/g, '')
    .replace(/\s+/g, '-')
    .replace(/-+/g, '-')
    .replace(/^-+|-+$/g, '')
    .slice(0, 100);
}

/**
 * AI Blog Generator Service
 */
export class AIBlogGeneratorService {
  /**
   * Check if the AI service is properly configured
   */
  static isConfigured(): boolean {
    return !!process.env.GOOGLE_API_KEY;
  }

  /**
   * Generate a complete blog post
   */
  static async generateBlogPost(
    input: BlogGenerationInput,
    createdBy: string
  ): Promise<BlogGenerationOutput> {
    const client = getGeminiClient();
    const startTime = Date.now();

    scopedLogger.info('Generating blog post', {
      topic: input.topic.slice(0, 50),
      language: input.language,
      tone: input.tone,
      wordCount: input.wordCount,
    });

    const wordCount = input.wordCount || 1000;
    const keywords = input.keywords?.join(', ') || '';

    // Build the generation prompt
    const prompt = input.language === 'ar'
      ? `أنت كاتب محتوى محترف متخصص في إنشاء مقالات مدونة محسّنة لمحركات البحث (SEO).

اكتب مقالة مدونة شاملة ومفصلة حول الموضوع التالي:
الموضوع: ${input.topic}
${keywords ? `الكلمات المفتاحية للتضمين: ${keywords}` : ''}
النبرة: ${input.tone === 'professional' ? 'مهنية ورسمية' : input.tone === 'casual' ? 'غير رسمية وودية' : 'معلوماتية وتعليمية'}
عدد الكلمات المستهدف: ${wordCount} كلمة

أنشئ المقالة بالتنسيق التالي (JSON):
{
  "title": "عنوان جذاب ومحسّن لمحركات البحث",
  "excerpt": "ملخص من 2-3 جمل يجذب القراء",
  "content": "محتوى المقالة بتنسيق Markdown مع عناوين فرعية (##) ونقاط مرقمة وفقرات منظمة",
  "tags": ["وسم1", "وسم2", "وسم3", "وسم4", "وسم5"],
  "seo": {
    "metaTitle": "عنوان ميتا (60 حرف كحد أقصى)",
    "metaDescription": "وصف ميتا جذاب (160 حرف كحد أقصى)",
    "keywords": ["كلمة1", "كلمة2", "كلمة3"]
  },
  "suggestedCoverImagePrompt": "وصف بالإنجليزية لصورة غلاف مناسبة للمقالة"
}

تأكد من:
1. المحتوى أصلي وقيّم للقراء
2. استخدام الكلمات المفتاحية بشكل طبيعي
3. تنظيم المحتوى بعناوين فرعية واضحة
4. إضافة قيمة حقيقية للقارئ`
      : `You are a professional content writer specializing in SEO-optimized blog articles.

Write a comprehensive and detailed blog article about the following topic:
Topic: ${input.topic}
${keywords ? `Keywords to include: ${keywords}` : ''}
Tone: ${input.tone}
Target word count: ${wordCount} words

Generate the article in the following JSON format:
{
  "title": "An engaging and SEO-optimized title",
  "excerpt": "A 2-3 sentence summary that hooks readers",
  "content": "The article content in Markdown format with subheadings (##), bullet points, and organized paragraphs",
  "tags": ["tag1", "tag2", "tag3", "tag4", "tag5"],
  "seo": {
    "metaTitle": "Meta title (60 characters max)",
    "metaDescription": "Compelling meta description (160 characters max)",
    "keywords": ["keyword1", "keyword2", "keyword3"]
  },
  "suggestedCoverImagePrompt": "A description for a suitable cover image for the article"
}

Ensure:
1. Content is original and valuable to readers
2. Keywords are used naturally throughout
3. Content is organized with clear subheadings
4. Provides real value to the reader`;

    try {
      const response = await client.models.generateContent({
        model: CONTENT_MODEL,
        contents: [{ role: 'user', parts: [{ text: prompt }] }],
        config: {
          responseMimeType: 'application/json',
        },
      });

      const responseText = response.text || '';

      // Parse the JSON response
      let parsed: BlogGenerationOutput;
      try {
        parsed = JSON.parse(responseText);
      } catch {
        // Try to extract JSON from the response if it's wrapped in markdown
        const jsonMatch = responseText.match(/```json\s*([\s\S]*?)\s*```/);
        if (jsonMatch) {
          parsed = JSON.parse(jsonMatch[1]);
        } else {
          throw new Error('Failed to parse AI response as JSON');
        }
      }

      // Generate slug from title
      const slug = generateSlug(parsed.title, input.language);

      const result: BlogGenerationOutput = {
        title: parsed.title,
        slug,
        excerpt: parsed.excerpt,
        content: parsed.content,
        tags: parsed.tags || [],
        seo: {
          metaTitle: parsed.seo?.metaTitle || parsed.title.slice(0, 60),
          metaDescription: parsed.seo?.metaDescription || parsed.excerpt.slice(0, 160),
          keywords: parsed.seo?.keywords || input.keywords || [],
        },
        suggestedCoverImagePrompt: parsed.suggestedCoverImagePrompt || '',
      };

      // Log the generation to database
      const tokensUsed = response.usageMetadata?.totalTokenCount;
      await this.logGeneration(
        'BLOG',
        prompt,
        JSON.stringify(result),
        CONTENT_MODEL,
        tokensUsed,
        createdBy
      );

      scopedLogger.info('Blog post generated successfully', {
        title: result.title.slice(0, 50),
        contentLength: result.content.length,
        tagsCount: result.tags.length,
        generationTimeMs: Date.now() - startTime,
      });

      return result;
    } catch (error) {
      scopedLogger.error('Failed to generate blog post', error);
      throw error;
    }
  }

  /**
   * Generate a social media adaptation of blog content
   */
  static async generateSocialAdaptation(
    blogContent: string,
    platform: SocialPlatform,
    createdBy: string
  ): Promise<SocialPost> {
    const client = getGeminiClient();
    const limits = PLATFORM_LIMITS[platform];

    scopedLogger.info('Generating social adaptation', {
      platform,
      contentLength: blogContent.length,
    });

    const prompt = `You are a social media expert. Adapt the following blog content for ${limits.name}.

Blog Content:
${blogContent.slice(0, 3000)}

Platform Requirements:
- Maximum characters: ${limits.maxChars}
- Maximum hashtags: ${limits.maxHashtags}
- ${limits.mediaRequired ? 'Media is REQUIRED' : 'Media is optional'}

Create an engaging ${limits.name} post that:
1. Hooks readers in the first line
2. Captures the key message of the blog
3. Uses appropriate tone for ${limits.name}
4. Includes a clear call-to-action
5. Uses relevant hashtags (exactly ${Math.min(limits.maxHashtags, platform === 'TWITTER' ? 3 : 10)} hashtags)

Respond in JSON format:
{
  "content": "The post content without hashtags",
  "hashtags": ["hashtag1", "hashtag2", ...],
  "mediaUrls": []
}

Important: The content MUST be under ${limits.maxChars} characters.`;

    try {
      const response = await client.models.generateContent({
        model: CONTENT_MODEL,
        contents: [{ role: 'user', parts: [{ text: prompt }] }],
        config: {
          responseMimeType: 'application/json',
        },
      });

      const responseText = response.text || '';

      let parsed: { content: string; hashtags: string[]; mediaUrls?: string[] };
      try {
        parsed = JSON.parse(responseText);
      } catch {
        const jsonMatch = responseText.match(/```json\s*([\s\S]*?)\s*```/);
        if (jsonMatch) {
          parsed = JSON.parse(jsonMatch[1]);
        } else {
          throw new Error('Failed to parse social adaptation response');
        }
      }

      // Ensure hashtags don't have # prefix (we'll add them when posting)
      const cleanHashtags = parsed.hashtags
        .map((tag: string) => tag.replace(/^#/, ''))
        .slice(0, limits.maxHashtags);

      // Truncate content if needed
      let content = parsed.content;
      if (content.length > limits.maxChars) {
        content = content.slice(0, limits.maxChars - 3) + '...';
      }

      const result: SocialPost = {
        content,
        hashtags: cleanHashtags,
        mediaUrls: parsed.mediaUrls || [],
        platform,
      };

      // Log the generation
      const tokensUsed = response.usageMetadata?.totalTokenCount;
      await this.logGeneration(
        'SOCIAL_POST',
        prompt.slice(0, 1000),
        JSON.stringify(result),
        CONTENT_MODEL,
        tokensUsed,
        createdBy
      );

      scopedLogger.info('Social adaptation generated', {
        platform,
        contentLength: result.content.length,
        hashtagCount: result.hashtags.length,
      });

      return result;
    } catch (error) {
      scopedLogger.error('Failed to generate social adaptation', error, { platform });
      throw error;
    }
  }

  /**
   * Generate adaptations for all platforms at once
   */
  static async generateAllSocialAdaptations(
    blogContent: string,
    createdBy: string
  ): Promise<SocialAdaptation[]> {
    const platforms: SocialPlatform[] = ['TWITTER', 'FACEBOOK', 'INSTAGRAM', 'TIKTOK'];
    const results: SocialAdaptation[] = [];

    for (const platform of platforms) {
      try {
        const post = await this.generateSocialAdaptation(blogContent, platform, createdBy);
        const limits = PLATFORM_LIMITS[platform];

        const warnings: string[] = [];
        if (post.content.length > limits.maxChars) {
          warnings.push(`Content exceeds ${limits.maxChars} character limit`);
        }
        if (limits.mediaRequired && post.mediaUrls.length === 0) {
          warnings.push(`${limits.name} requires media`);
        }

        results.push({
          platform,
          content: post.content,
          hashtags: post.hashtags,
          characterCount: post.content.length,
          isValid: warnings.length === 0,
          warnings,
        });
      } catch (error) {
        scopedLogger.error('Failed to generate adaptation for platform', error, { platform });
        results.push({
          platform,
          content: '',
          hashtags: [],
          characterCount: 0,
          isValid: false,
          warnings: ['Failed to generate adaptation'],
        });
      }
    }

    return results;
  }

  /**
   * Generate a cover image prompt based on blog title and excerpt
   */
  static async generateCoverImagePrompt(
    title: string,
    excerpt: string,
    createdBy: string
  ): Promise<string> {
    const client = getGeminiClient();

    scopedLogger.info('Generating cover image prompt', {
      titleLength: title.length,
    });

    const prompt = `You are an expert at creating prompts for AI image generators.

Based on the following blog post details, create a detailed image generation prompt for a professional cover image:

Title: ${title}
Summary: ${excerpt}

Create a prompt that will generate:
1. A professional, visually appealing image
2. Suitable for a blog header/cover
3. Modern and clean aesthetic
4. No text in the image (text will be overlaid separately)

Respond with ONLY the image generation prompt, nothing else. Keep it under 500 characters.`;

    try {
      const response = await client.models.generateContent({
        model: CONTENT_MODEL,
        contents: [{ role: 'user', parts: [{ text: prompt }] }],
      });

      const imagePrompt = response.text?.trim() || '';

      // Log the generation
      const tokensUsed = response.usageMetadata?.totalTokenCount;
      await this.logGeneration(
        'IMAGE',
        prompt,
        imagePrompt,
        CONTENT_MODEL,
        tokensUsed,
        createdBy
      );

      scopedLogger.info('Cover image prompt generated', {
        promptLength: imagePrompt.length,
      });

      return imagePrompt;
    } catch (error) {
      scopedLogger.error('Failed to generate cover image prompt', error);
      throw error;
    }
  }

  /**
   * Log AI content generation to database
   */
  private static async logGeneration(
    contentType: 'BLOG' | 'SOCIAL_POST' | 'IMAGE',
    inputPrompt: string,
    outputContent: string,
    model: string,
    tokens: number | undefined,
    createdBy: string
  ): Promise<void> {
    try {
      await prisma.ai_content_generations.create({
        data: {
          id: createId(),
          contentType,
          inputPrompt: inputPrompt.slice(0, 10000), // Limit stored prompt size
          outputContent: outputContent.slice(0, 50000), // Limit stored output size
          model,
          tokens: tokens || null,
          createdBy,
          createdAt: new Date(),
        },
      });
    } catch (error) {
      // Log error but don't fail the main operation
      scopedLogger.error('Failed to log AI generation', error);
    }
  }

  /**
   * Get generation history for a user
   */
  static async getGenerationHistory(
    createdBy: string,
    options?: {
      contentType?: 'BLOG' | 'SOCIAL_POST' | 'IMAGE';
      limit?: number;
      offset?: number;
    }
  ): Promise<{
    generations: Array<{
      id: string;
      contentType: string;
      model: string;
      tokens: number | null;
      createdAt: Date;
    }>;
    total: number;
  }> {
    const where = {
      createdBy,
      ...(options?.contentType && { contentType: options.contentType }),
    };

    const [generations, total] = await Promise.all([
      prisma.ai_content_generations.findMany({
        where,
        select: {
          id: true,
          contentType: true,
          model: true,
          tokens: true,
          createdAt: true,
        },
        orderBy: { createdAt: 'desc' },
        take: options?.limit || 50,
        skip: options?.offset || 0,
      }),
      prisma.ai_content_generations.count({ where }),
    ]);

    return { generations, total };
  }
}

// Export singleton-style functions for convenience
export const aiBlogGeneratorService = {
  isConfigured: AIBlogGeneratorService.isConfigured.bind(AIBlogGeneratorService),
  generateBlogPost: AIBlogGeneratorService.generateBlogPost.bind(AIBlogGeneratorService),
  generateSocialAdaptation: AIBlogGeneratorService.generateSocialAdaptation.bind(AIBlogGeneratorService),
  generateAllSocialAdaptations: AIBlogGeneratorService.generateAllSocialAdaptations.bind(AIBlogGeneratorService),
  generateCoverImagePrompt: AIBlogGeneratorService.generateCoverImagePrompt.bind(AIBlogGeneratorService),
  getGenerationHistory: AIBlogGeneratorService.getGenerationHistory.bind(AIBlogGeneratorService),
};
