import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ShareEvent, SharePlatform } from './analytics.entity';
import { Article } from '../entities';
import {
  TrackShareDto,
  GetShareStatsDto,
  ShareStatsResponse,
} from './analytics.dto';

@Injectable()
export class AnalyticsService {
  private readonly logger = new Logger(AnalyticsService.name);

  constructor(
    @InjectRepository(ShareEvent)
    private readonly shareEventRepository: Repository<ShareEvent>,
    @InjectRepository(Article)
    private readonly articleRepository: Repository<Article>,
  ) {}

  async trackShare(trackShareDto: TrackShareDto): Promise<ShareEvent> {
    const shareEvent = this.shareEventRepository.create(trackShareDto);

    // Also update the article's share counters
    await this.incrementArticleShareCounter(
      trackShareDto.articleId,
      trackShareDto.platform,
    );

    return await this.shareEventRepository.save(shareEvent);
  }

  private async incrementArticleShareCounter(
    articleId: string,
    platform: SharePlatform,
  ): Promise<void> {
    const updateField = this.getShareCounterField(platform);
    if (!updateField) return;

    await this.articleRepository
      .createQueryBuilder()
      .update(Article)
      .set({ [updateField]: () => `${updateField} + 1` })
      .where('id = :id', { id: articleId })
      .execute();
  }

  private getShareCounterField(platform: SharePlatform): string | null {
    switch (platform) {
      case 'facebook':
        return 'facebookShares';
      case 'twitter':
        return 'twitterShares';
      case 'whatsapp':
        return 'whatsappShares';
      case 'telegram':
        return 'telegramShares';
      default:
        return null; // 'link' shares don't increment counters
    }
  }

  async getShareStats(
    getShareStatsDto: GetShareStatsDto,
  ): Promise<ShareStatsResponse[]> {
    const query = this.articleRepository
      .createQueryBuilder('article')
      .select([
        'article.id as "articleId"',
        'article.title as "articleTitle"',
        'article.facebookShares as "facebookShares"',
        'article.twitterShares as "twitterShares"',
        'article.whatsappShares as "whatsappShares"',
        'article.telegramShares as "telegramShares"',
        'article.views as "views"',
        'article.createdAt as "createdAt"',
        'article.updatedAt as "updatedAt"',
      ])
      .addSelect(
        `(article.facebookShares + article.twitterShares + article.whatsappShares + article.telegramShares) as "totalShares"`,
      )
      .addSelect(
        `CASE 
          WHEN article.views > 0 
          THEN ROUND(
            (article.facebookShares + article.twitterShares + article.whatsappShares + article.telegramShares)::decimal / article.views * 100, 
            2
          )
          ELSE 0 
        END as "shareRate"`,
      );

    if (getShareStatsDto.articleId) {
      query.where('article.id = :articleId', {
        articleId: getShareStatsDto.articleId,
      });
    }

    if (getShareStatsDto.startDate) {
      query.andWhere('article.createdAt >= :startDate', {
        startDate: getShareStatsDto.startDate,
      });
    }

    if (getShareStatsDto.endDate) {
      query.andWhere('article.createdAt <= :endDate', {
        endDate: getShareStatsDto.endDate,
      });
    }

    query.orderBy('"totalShares"', 'DESC');

    const rawResults = await query.getRawMany<{
      articleId: string;
      articleTitle: string;
      facebookShares: string;
      twitterShares: string;
      whatsappShares: string;
      telegramShares: string;
      views: string;
      createdAt: string;
      updatedAt: string;
      totalShares: string;
      shareRate: string;
    }>();

    // Get link shares from share_events table
    const results: ShareStatsResponse[] = [];
    for (const rawResult of rawResults) {
      const linkShares = await this.shareEventRepository.count({
        where: {
          articleId: rawResult.articleId,
          platform: 'link',
        },
      });

      const facebookShares = parseInt(rawResult.facebookShares) || 0;
      const twitterShares = parseInt(rawResult.twitterShares) || 0;
      const whatsappShares = parseInt(rawResult.whatsappShares) || 0;
      const telegramShares = parseInt(rawResult.telegramShares) || 0;
      const views = parseInt(rawResult.views) || 0;
      const baseTotalShares =
        facebookShares + twitterShares + whatsappShares + telegramShares;
      const totalShares = baseTotalShares + linkShares;
      const shareRate =
        views > 0 ? parseFloat(((totalShares / views) * 100).toFixed(2)) : 0;

      results.push({
        articleId: rawResult.articleId,
        articleTitle: rawResult.articleTitle,
        facebookShares,
        twitterShares,
        whatsappShares,
        telegramShares,
        linkShares,
        totalShares,
        views,
        shareRate,
        createdAt: new Date(rawResult.createdAt),
        updatedAt: new Date(rawResult.updatedAt),
      });
    }

    return results;
  }

  async getTopSharedArticles(
    limit: number = 10,
  ): Promise<ShareStatsResponse[]> {
    const stats = await this.getShareStats({});
    return stats.slice(0, limit);
  }

  async getShareTrends(
    startDate: Date,
    endDate: Date,
    interval: 'day' | 'week' | 'month' = 'day',
  ): Promise<
    Array<{ period: string; platform: SharePlatform; count: number }>
  > {
    const dateFormat =
      interval === 'day'
        ? 'YYYY-MM-DD'
        : interval === 'week'
          ? 'YYYY-WW'
          : 'YYYY-MM';

    const query = this.shareEventRepository
      .createQueryBuilder('share_event')
      .select([
        `TO_CHAR(share_event.createdAt, '${dateFormat}') as period`,
        'share_event.platform as platform',
        'COUNT(*) as count',
      ])
      .where('share_event.createdAt >= :startDate', { startDate })
      .andWhere('share_event.createdAt <= :endDate', { endDate })
      .groupBy('period, platform')
      .orderBy('period', 'ASC');

    const rawResults = await query.getRawMany<{
      period: string;
      platform: string;
      count: string;
    }>();

    // Convert platform strings to SharePlatform type
    return rawResults.map((result) => ({
      period: result.period,
      platform: result.platform as SharePlatform,
      count: parseInt(result.count) || 0,
    }));
  }

  async getTotalShareStats(): Promise<{
    totalShares: number;
    facebookShares: number;
    twitterShares: number;
    whatsappShares: number;
    telegramShares: number;
    linkShares: number;
  }> {
    interface ArticleStatsRaw {
      facebookShares: string;
      twitterShares: string;
      whatsappShares: string;
      telegramShares: string;
    }

    const articleStats = (await this.articleRepository
      .createQueryBuilder('article')
      .select([
        'SUM(article.facebookShares) as facebookShares',
        'SUM(article.twitterShares) as twitterShares',
        'SUM(article.whatsappShares) as whatsappShares',
        'SUM(article.telegramShares) as telegramShares',
      ])
      .getRawOne()) as ArticleStatsRaw;

    const linkShares = await this.shareEventRepository.count({
      where: { platform: 'link' },
    });

    const facebookShares = parseInt(articleStats?.facebookShares || '0') || 0;
    const twitterShares = parseInt(articleStats?.twitterShares || '0') || 0;
    const whatsappShares = parseInt(articleStats?.whatsappShares || '0') || 0;
    const telegramShares = parseInt(articleStats?.telegramShares || '0') || 0;

    const totalShares =
      facebookShares +
      twitterShares +
      whatsappShares +
      telegramShares +
      linkShares;

    return {
      totalShares,
      facebookShares,
      twitterShares,
      whatsappShares,
      telegramShares,
      linkShares,
    };
  }
}
