/**
 * Social Posting Service
 * Handles posting content to social media platforms
 *
 * @module lib/services/social-posting.service
 */

import { logger } from '@/lib/logger';
import {
  socialAccountsAdapter,
  socialContentQueueAdapter,
} from '@/lib/adapters/social';
import { getAccessToken } from './social-auth.service';
import type {
  SocialPost,
  PostResult,
  QueueItemOutput,
  SocialPlatform,
} from '@/lib/types/social-media.types';

const MAX_RETRIES = 3;

export class SocialPostingService {
  /**
   * Post content to Facebook
   */
  async postToFacebook(accountId: string, content: SocialPost): Promise<PostResult> {
    try {
      const accessToken = await getAccessToken(accountId);

      // Get account to retrieve page info
      const account = await socialAccountsAdapter.findUnique({
        where: { id: accountId },
      });

      if (!account) {
        return { success: false, error: 'Account not found', retryable: false };
      }

      const accountRecord = account as Record<string, unknown>;
      const pageId = accountRecord.platformAccountId as string;
      const metadata = accountRecord.metadata as { pageAccessToken?: string } | null;
      const pageAccessToken = metadata?.pageAccessToken || accessToken;

      // Build post message with hashtags
      const message = this.buildPostMessage(content);

      // Determine post type
      if (content.mediaUrls.length > 0) {
        return await this.postFacebookWithMedia(pageId, pageAccessToken, message, content.mediaUrls);
      } else {
        return await this.postFacebookText(pageId, pageAccessToken, message);
      }
    } catch (error) {
      logger.error('Facebook posting failed', { error, accountId });
      return {
        success: false,
        error: error instanceof Error ? error.message : 'Unknown error',
        retryable: true,
      };
    }
  }

  /**
   * Post content to Instagram
   */
  async postToInstagram(accountId: string, content: SocialPost): Promise<PostResult> {
    try {
      if (content.mediaUrls.length === 0) {
        return {
          success: false,
          error: 'Instagram requires at least one image or video',
          retryable: false,
        };
      }

      const accessToken = await getAccessToken(accountId);

      const account = await socialAccountsAdapter.findUnique({
        where: { id: accountId },
      });

      if (!account) {
        return { success: false, error: 'Account not found', retryable: false };
      }

      const accountRecord = account as Record<string, unknown>;
      const igUserId = accountRecord.platformAccountId as string;
      const message = this.buildPostMessage(content);

      // Instagram posting is a two-step process
      // Step 1: Create media container
      const containerId = await this.createInstagramMediaContainer(
        igUserId,
        accessToken,
        content.mediaUrls[0],
        message
      );

      // Step 2: Publish the container
      return await this.publishInstagramContainer(igUserId, accessToken, containerId);
    } catch (error) {
      logger.error('Instagram posting failed', { error, accountId });
      return {
        success: false,
        error: error instanceof Error ? error.message : 'Unknown error',
        retryable: true,
      };
    }
  }

  /**
   * Publish a queue item to its platform
   */
  async publishQueueItem(queueItemId: string): Promise<PostResult> {
    const queueItem = await socialContentQueueAdapter.findUnique({
      where: { id: queueItemId },
      include: { social_account: true },
    });

    if (!queueItem) {
      return { success: false, error: 'Queue item not found', retryable: false };
    }

    const queueRecord = queueItem as Record<string, unknown>;

    if (queueRecord.status === 'PUBLISHED') {
      return { success: false, error: 'Already published', retryable: false };
    }

    // Update status to publishing
    await socialContentQueueAdapter.update({
      where: { id: queueItemId },
      data: { status: 'PUBLISHING' },
    });

    const content: SocialPost = {
      content: queueRecord.content as string,
      hashtags: queueRecord.hashtags as string[],
      mediaUrls: queueRecord.mediaUrls as string[],
      platform: queueRecord.platform as SocialPlatform,
    };

    let result: PostResult;

    switch (queueRecord.platform) {
      case 'FACEBOOK':
        result = await this.postToFacebook(queueRecord.socialAccountId as string, content);
        break;
      case 'INSTAGRAM':
        result = await this.postToInstagram(queueRecord.socialAccountId as string, content);
        break;
      case 'TWITTER':
        result = { success: false, error: 'Twitter posting coming soon', retryable: false };
        break;
      case 'TIKTOK':
        result = { success: false, error: 'TikTok posting coming soon', retryable: false };
        break;
      default:
        result = { success: false, error: `Unsupported platform: ${queueRecord.platform as string}`, retryable: false };
    }

    // Update queue item with result
    await socialContentQueueAdapter.update({
      where: { id: queueItemId },
      data: {
        status: result.success ? 'PUBLISHED' : 'FAILED',
        publishedAt: result.success ? new Date() : null,
        platformPostId: result.platformPostId || null,
        platformUrl: result.platformUrl || null,
        errorMessage: result.error || null,
        retryCount: result.success
          ? queueRecord.retryCount as number
          : (queueRecord.retryCount as number) + 1,
      },
    });

    if (result.success) {
      logger.info('Queue item published', { queueItemId, platform: queueRecord.platform });
    } else {
      logger.warn('Queue item publishing failed', { queueItemId, error: result.error });
    }

    return result;
  }

  /**
   * Retry a failed queue item
   */
  async retryFailedPost(queueItemId: string): Promise<PostResult> {
    const queueItem = await socialContentQueueAdapter.findUnique({
      where: { id: queueItemId },
    });

    if (!queueItem) {
      return { success: false, error: 'Queue item not found', retryable: false };
    }

    const queueRecord = queueItem as Record<string, unknown>;

    if (queueRecord.status !== 'FAILED') {
      return { success: false, error: 'Queue item is not in failed state', retryable: false };
    }

    if ((queueRecord.retryCount as number) >= MAX_RETRIES) {
      return { success: false, error: 'Maximum retry attempts exceeded', retryable: false };
    }

    return await this.publishQueueItem(queueItemId);
  }

  /**
   * Get queue items that are scheduled and ready to publish
   */
  async getScheduledItemsToPublish(): Promise<QueueItemOutput[]> {
    const now = new Date();

    const items = await socialContentQueueAdapter.findMany({
      where: {
        status: 'SCHEDULED',
        scheduledAt: { lte: now },
      },
      orderBy: { scheduledAt: 'asc' },
    });

    return items as QueueItemOutput[];
  }

  /**
   * Process all scheduled items that are ready
   */
  async processScheduledPosts(): Promise<{ processed: number; success: number; failed: number }> {
    const items = await this.getScheduledItemsToPublish();

    let success = 0;
    let failed = 0;

    for (const item of items) {
      const result = await this.publishQueueItem(item.id);
      if (result.success) {
        success++;
      } else {
        failed++;
      }
    }

    return { processed: items.length, success, failed };
  }

  // === Private Helper Methods ===

  private buildPostMessage(content: SocialPost): string {
    let message = content.content;

    if (content.hashtags.length > 0) {
      const hashtags = content.hashtags
        .map(tag => (tag.startsWith('#') ? tag : `#${tag}`))
        .join(' ');
      message += '\n\n' + hashtags;
    }

    return message;
  }

  private async postFacebookText(
    pageId: string,
    accessToken: string,
    message: string
  ): Promise<PostResult> {
    const response = await fetch(
      `https://graph.facebook.com/v19.0/${pageId}/feed`,
      {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          message,
          access_token: accessToken,
        }),
      }
    );

    const data = await response.json();

    if (!response.ok) {
      return {
        success: false,
        error: data.error?.message || 'Facebook API error',
        retryable: response.status >= 500,
      };
    }

    return {
      success: true,
      platformPostId: data.id,
      platformUrl: `https://www.facebook.com/${data.id}`,
    };
  }

  private async postFacebookWithMedia(
    pageId: string,
    accessToken: string,
    message: string,
    mediaUrls: string[]
  ): Promise<PostResult> {
    // For simplicity, post first image as a photo post
    const imageUrl = mediaUrls[0];

    const response = await fetch(
      `https://graph.facebook.com/v19.0/${pageId}/photos`,
      {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          url: imageUrl,
          caption: message,
          access_token: accessToken,
        }),
      }
    );

    const data = await response.json();

    if (!response.ok) {
      return {
        success: false,
        error: data.error?.message || 'Facebook API error',
        retryable: response.status >= 500,
      };
    }

    return {
      success: true,
      platformPostId: data.id,
      platformUrl: `https://www.facebook.com/${data.id}`,
    };
  }

  private async createInstagramMediaContainer(
    igUserId: string,
    accessToken: string,
    imageUrl: string,
    caption: string
  ): Promise<string> {
    const response = await fetch(
      `https://graph.facebook.com/v19.0/${igUserId}/media`,
      {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          image_url: imageUrl,
          caption,
          access_token: accessToken,
        }),
      }
    );

    const data = await response.json();

    if (!response.ok) {
      throw new Error(data.error?.message || 'Failed to create Instagram media container');
    }

    return data.id;
  }

  private async publishInstagramContainer(
    igUserId: string,
    accessToken: string,
    containerId: string
  ): Promise<PostResult> {
    const response = await fetch(
      `https://graph.facebook.com/v19.0/${igUserId}/media_publish`,
      {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          creation_id: containerId,
          access_token: accessToken,
        }),
      }
    );

    const data = await response.json();

    if (!response.ok) {
      return {
        success: false,
        error: data.error?.message || 'Failed to publish Instagram post',
        retryable: response.status >= 500,
      };
    }

    return {
      success: true,
      platformPostId: data.id,
      platformUrl: `https://www.instagram.com/p/${data.id}`,
    };
  }
}

// Export singleton instance
export const socialPosting = new SocialPostingService();
