# frozen_string_literal: true

module DiscourseAi
  module Sentiment
    class EntryPoint
      def inject_into(plugin)
        sentiment_analysis_cb =
          Proc.new do |post|
            if SiteSetting.ai_sentiment_enabled
              Jobs.enqueue(:post_sentiment_analysis, post_id: post.id)
            end
          end

        plugin.on(:post_created, &sentiment_analysis_cb)
        plugin.on(:post_edited, &sentiment_analysis_cb)

        plugin.add_report("overall_sentiment") do |report|
          report.modes = [:stacked_chart]
          threshold = 60

          sentiment_count_sql = Proc.new { |sentiment| <<~SQL }
            COUNT(
              CASE WHEN (cr.classification::jsonb->'#{sentiment}')::integer > :threshold THEN 1 ELSE NULL END
            ) AS #{sentiment}_count
          SQL

          grouped_sentiments =
            DB.query(
              <<~SQL,
            SELECT
              DATE_TRUNC('day', p.created_at)::DATE AS posted_at,
              #{sentiment_count_sql.call("positive")},
              -#{sentiment_count_sql.call("negative")}
            FROM
              classification_results AS cr
            INNER JOIN posts p ON p.id = cr.target_id AND cr.target_type = 'Post'
            INNER JOIN topics t ON t.id = p.topic_id
            INNER JOIN categories c ON c.id = t.category_id
            WHERE
              t.archetype = 'regular' AND
              p.user_id > 0 AND
              cr.model_used = 'sentiment' AND
              (p.created_at > :report_start AND p.created_at < :report_end)
            GROUP BY DATE_TRUNC('day', p.created_at)
          SQL
              report_start: report.start_date,
              report_end: report.end_date,
              threshold: threshold,
            )

          data_points = %w[positive negative]

          return report if grouped_sentiments.empty?

          report.data =
            data_points.map do |point|
              {
                req: "sentiment_#{point}",
                color: point == "positive" ? report.colors[:lime] : report.colors[:purple],
                label: I18n.t("discourse_ai.sentiment.reports.overall_sentiment.#{point}"),
                data:
                  grouped_sentiments.map do |gs|
                    { x: gs.posted_at, y: gs.public_send("#{point}_count") }
                  end,
              }
            end
        end

        plugin.add_report("post_emotion") do |report|
          report.modes = [:stacked_line_chart]
          threshold = 30

          emotion_count_clause = Proc.new { |emotion| <<~SQL }
    COUNT(
      CASE WHEN (cr.classification::jsonb->'#{emotion}')::integer > :threshold THEN 1 ELSE NULL END
    ) AS #{emotion}_count
  SQL

          grouped_emotions =
            DB.query(
              <<~SQL,
      SELECT
        DATE_TRUNC('day', p.created_at)::DATE AS posted_at,
        #{emotion_count_clause.call("sadness")},
        #{emotion_count_clause.call("surprise")},
        #{emotion_count_clause.call("fear")},
        #{emotion_count_clause.call("anger")},
        #{emotion_count_clause.call("joy")},
        #{emotion_count_clause.call("disgust")}
      FROM
        classification_results AS cr
      INNER JOIN posts p ON p.id = cr.target_id AND cr.target_type = 'Post'
      INNER JOIN users u ON p.user_id = u.id
      INNER JOIN topics t ON t.id = p.topic_id
      INNER JOIN categories c ON c.id = t.category_id
      WHERE
        t.archetype = 'regular' AND
        p.user_id > 0 AND
        cr.model_used = 'emotion' AND
        (p.created_at > :report_start AND p.created_at < :report_end)
      GROUP BY DATE_TRUNC('day', p.created_at)
      SQL
              report_start: report.start_date,
              report_end: report.end_date,
              threshold: threshold,
            )

          return report if grouped_emotions.empty?

          emotions = [
            { name: "sadness", color: report.colors[:turquoise] },
            { name: "disgust", color: report.colors[:lime] },
            { name: "fear", color: report.colors[:purple] },
            { name: "anger", color: report.colors[:magenta] },
            { name: "joy", color: report.colors[:yellow] },
            { name: "surprise", color: report.colors[:brown] },
          ]

          report.data =
            emotions.map do |emotion|
              {
                req: "emotion_#{emotion[:name]}",
                color: emotion[:color],
                label: I18n.t("discourse_ai.sentiment.reports.post_emotion.#{emotion[:name]}"),
                data:
                  grouped_emotions.map do |ge|
                    { x: ge.posted_at, y: ge.public_send("#{emotion[:name]}_count") }
                  end,
              }
            end
        end
      end
    end
  end
end
