# frozen_string_literal: true

class Core::UseCases::MonitoringAlerts::IngestFromHologres < Core::UseCases::AbstractUsecase
  include Dry::Monads[:result]

  def initialize
    @processed_count = 0
    @created_count = 0
    @updated_count = 0
    @skipped_count = 0
    @failed_count = 0
    @errors = []
  end

  def call
    # Fetch data from Hologres
    hologres_result = fetch_from_hologres
    return hologres_result if hologres_result.failure?

    records = hologres_result.value!

    # Process each record
    records.each do |record|
      process_record(record)
    end

    Success(
      processed_count: @processed_count,
      created_count:   @created_count,
      updated_count:   @updated_count,
      skipped_count:   @skipped_count,
      failed_count:    @failed_count,
      errors:          @errors
    )
  end

  private

  def fetch_from_hologres
    query = build_hologres_query

    hologres_service = Core::Services::Hologres::Query.new(
                         database_name: ENV['HOLOGRES_CHAT_NAME'],
                         user:          ENV['HOLOGRES_CHAT_USERNAME'],
                         password:      ENV['HOLOGRES_CHAT_PASSWORD'],
                         host:          ENV['HOLOGRES_CHAT_HOSTNAME'],
                         port:          ENV['HOLOGRES_CHAT_PORT']
    )

    result = hologres_service.call_params(query, ['Anomaly'])

    return result if result.failure?

    # Convert PG::Result to array of hashes
    Success(result.value!.to_a)
  end

  def build_hologres_query
    schema = ENV['HOLOGRES_BALANCE_ANOMALY_SCHEMA']
    table = ENV['HOLOGRES_REPORT_SERVICE_TABLE']

    <<-SQL
      SELECT
        "#{table}"."#{schema}"."company_id" AS "company_id",
        "#{table}"."#{schema}"."company_name" AS "company_name",
        "#{table}"."#{schema}"."organization_id" AS "organization_id",
        "#{table}"."#{schema}"."diff_balance_amount" AS "diff_balance_amount",
        "#{table}"."#{schema}"."alert_detail" AS "alert_detail",
        "#{table}"."#{schema}"."report_date" AS "report_date",
        "#{table}"."#{schema}"."anomaly_status" AS "anomaly_status"
      FROM
        "#{table}"."#{schema}"
      WHERE
        anomaly_status = $1
    SQL
  end

  def process_record(record)
    @processed_count += 1

    external_company_id = record['company_id']

    # Skip if company_id is missing
    if external_company_id.blank?
      @failed_count += 1
      @errors << { company_id: external_company_id, error: 'Missing company_id' }
      return
    end

    # Find existing alert
    existing_alert_result = Core::Repositories::MonitoringAlerts::FindByExternalCompanyId.new(
                              external_company_id: external_company_id
    ).call

    return if existing_alert_result.failure?

    existing_alert = existing_alert_result.value!

    apply_business_rules(existing_alert, record)
  rescue => e
    @failed_count += 1
    @errors << { company_id: record['company_id'], error: e.message }
  end

  def apply_business_rules(existing_alert, record)
    if existing_alert.nil?
      # No existing alert -> create with status 'open'
      create_alert(record)
    elsif existing_alert.current_status == 'open'
      # Status is 'open' -> update with new data
      update_alert(existing_alert, record)
    elsif existing_alert.current_status == 'in_progress'
      # Status is 'in_progress' -> skip
      @skipped_count += 1
    elsif existing_alert.current_status == 'fixed'
      # Status is 'fixed' -> create new alert with status 'open'
      create_alert(record)
    else
      # Other statuses (like 'on_hold') -> skip by default
      @skipped_count += 1
    end
  end

  def create_alert(record)
    alert = MonitoringAlert.new(
              external_company_id: record['company_id'],
              company_name:        record['company_name'],
              balance_difference:  parse_float(record['diff_balance_amount']),
              alert_detail:        record['alert_detail'] || '',
              reported_date:       parse_date(record['report_date']),
              current_status:      'open'
    )

    if alert.save
      @created_count += 1
    else
      @failed_count += 1
      @errors << { company_id: record['company_id'], error: alert.errors.full_messages.join(', ') }
    end
  end

  def update_alert(existing_alert, record)
    existing_alert.company_name = record['company_name']
    existing_alert.balance_difference = parse_float(record['diff_balance_amount'])
    existing_alert.alert_detail = record['alert_detail'] || ''
    existing_alert.reported_date = parse_date(record['report_date'])

    if existing_alert.save
      @updated_count += 1
    else
      @failed_count += 1
      @errors << { company_id: record['company_id'], error: existing_alert.errors.full_messages.join(', ') }
    end
  end

  def parse_float(value)
    return 0.0 if value.blank?

    # Remove commas if present and convert to float
    value.to_s.delete(',').to_f
  end

  def parse_date(date_string)
    return Time.current if date_string.blank?

    # Try parsing as ISO format first, then fall back to natural language parsing
    Time.zone.parse(date_string)
  rescue ArgumentError
    Time.current
  end
end
