# Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/

class TimeAccountingsController < ApplicationController
  prepend_before_action :authenticate_and_authorize!

  def index
    model_index_render(ticket_time_accounting_scope, params)
  end

  def show
    model_show_render(ticket_time_accounting_scope, params)
  end

  def create
    model_create_render(ticket_time_accounting_scope, params)
  end

  def update
    model_update_render(ticket_time_accounting_scope, params)
  end

  def destroy
    model_references_check(Ticket::TimeAccounting, params)
    model_destroy_render(ticket_time_accounting_scope, params)
  end

  def by_activity
    year  = params[:year] || Time.zone.now.year
    month = params[:month] || Time.zone.now.month

    start_period = Time.zone.parse("#{year}-#{month}-01")
    end_period   = start_period.end_of_month

    records = Ticket::TimeAccounting
      .where(created_at: (start_period..end_period))
      .pluck(:ticket_id, :ticket_article_id, :time_unit, :type_id, :created_by_id, :created_at)

    customers     = {}
    organizations = {}
    types         = {}
    agents        = {}
    results       = []
    records.each do |record|
      ticket = Ticket.lookup(id: record[0])
      next if !ticket

      customers[ticket.customer_id]         ||= User.lookup(id: ticket.customer_id).fullname
      organizations[ticket.organization_id] ||= Organization.lookup(id: ticket.organization_id)&.name
      types[record[3]]                      ||= Ticket::TimeAccounting::Type.lookup(id: record[3])&.name
      agents[record[4]]                     ||= User.lookup(id: record[4])

      result = if params[:download]
                 [
                   ticket.number,
                   ticket.title,
                   customers[ticket.customer_id] || '-',
                   organizations[ticket.organization_id] || '-',
                   agents[record[4]].fullname,
                   agents[record[4]].login,
                   record[2],
                   *([types[record[3]] || '-'] if Setting.get('time_accounting_types')),
                   record[5]
                 ]
               else
                 {
                   ticket:       ticket.attributes,
                   time_unit:    record[2],
                   type:         (types[record[3]] || '-' if Setting.get('time_accounting_types')),
                   customer:     customers[ticket.customer_id] || '-',
                   organization: organizations[ticket.organization_id] || '-',
                   agent:        agents[record[4]].fullname,
                   created_at:   record[5],
                 }.compact
               end

      results.push result
    end

    if !params[:download]
      results = results.last(params[:limit].to_i) if params[:limit]
      render json: results
      return
    end

    header = [
      {
        name:  __('Ticket#'),
        width: 20,
      },
      {
        name:  __('Title'),
        width: 20,
      },
      {
        name:  "#{__('Customer')} - #{__('Name')}",
        width: 20,
      },
      {
        name:  __('Organization'),
        width: 20,
      },
      {
        name:  "#{__('Agent')} - #{__('Name')}",
        width: 20,
      },
      {
        name:  "#{__('Agent')} - #{__('Login')}",
        width: 20,
      },
      {
        name:      __('Time Units'),
        width:     10,
        data_type: 'float'
      },
      *(if Setting.get('time_accounting_types')
          [{
            name:  __('Activity Type'),
            width: 20,
          }]
        end),
      {
        name:      __('Created at'),
        width:     20,
        data_type: 'datetime',
      },
    ]

    excel = ExcelSheet.new(
      title:    "By Activity #{year}-#{month}",
      header:   header,
      records:  results,
      timezone: params[:timezone],
      locale:   current_user.locale,
    )
    send_data(
      excel.content,
      filename:    "by_activity-#{year}-#{month}.xlsx",
      type:        ExcelSheet::CONTENT_TYPE,
      disposition: 'attachment'
    )
  end

  def by_ticket
    year  = params[:year] || Time.zone.now.year
    month = params[:month] || Time.zone.now.month

    start_period = Time.zone.parse("#{year}-#{month}-01")
    end_period   = start_period.end_of_month

    time_unit = Ticket::TimeAccounting
      .where(created_at: (start_period..end_period))
      .pluck(:ticket_id, :time_unit, :created_by_id)
      .each_with_object({}) do |record, memo|
        if !memo[record[0]]
          memo[record[0]] = {
            time_unit: 0,
            agent_id:  record[2],
          }
        end
        memo[record[0]][:time_unit] += record[1]
      end

    if !params[:download]
      customers = {}
      organizations = {}
      agents = {}
      results = []
      time_unit.each do |ticket_id, local_time_unit|
        ticket = Ticket.lookup(id: ticket_id)
        next if !ticket

        customers[ticket.customer_id]         ||= User.lookup(id: ticket.customer_id).fullname
        organizations[ticket.organization_id] ||= Organization.lookup(id: ticket.organization_id)&.name
        agents[local_time_unit[:agent_id]]    ||= User.lookup(id: local_time_unit[:agent_id]).fullname

        result = {
          ticket:       ticket.attributes,
          time_unit:    local_time_unit[:time_unit],
          customer:     customers[ticket.customer_id] || '-',
          organization: organizations[ticket.organization_id] || '-',
          agent:        agents[local_time_unit[:agent_id]],
        }
        results.push result
      end

      results = results.last(params[:limit].to_i) if params[:limit]
      render json: results
      return
    end

    ticket_ids = []
    additional_attributes = []
    additional_attributes_header = [{ display: __('Time Units'), name: 'time_unit_for_range', width: 10, data_type: 'float' }]
    time_unit.each do |ticket_id, local_time_unit|
      ticket_ids.push ticket_id
      additional_attribute = {
        time_unit_for_range: local_time_unit[:time_unit],
      }
      additional_attributes.push additional_attribute
    end

    excel = ExcelSheet::Ticket.new(
      title:                        "Tickets: #{year}-#{month}",
      ticket_ids:                   ticket_ids,
      additional_attributes:        additional_attributes,
      additional_attributes_header: additional_attributes_header,
      timezone:                     params[:timezone],
      locale:                       current_user.locale,
    )

    send_data(
      excel.content,
      filename:    "by_ticket-#{year}-#{month}.xlsx",
      type:        ExcelSheet::CONTENT_TYPE,
      disposition: 'attachment'
    )
  end

  def by_customer
    year  = params[:year] || Time.zone.now.year
    month = params[:month] || Time.zone.now.month

    start_period = Time.zone.parse("#{year}-#{month}-01")
    end_period   = start_period.end_of_month

    results = Ticket::TimeAccounting
      .where(created_at: (start_period..end_period))
      .pluck(:ticket_id, :time_unit, :created_by_id)
      .each_with_object({}) do |record, memo|
        memo[record[0]] ||= {
          time_unit: 0,
          agent_id:  record[2],
        }
        memo[record[0]][:time_unit] += record[1]
      end
      .each_with_object({}) do |(ticket_id, local_time_unit), memo|
        ticket = Ticket.lookup(id: ticket_id)
        next if !ticket

        memo[ticket.customer_id] ||= {}
        memo[ticket.customer_id][ticket.organization_id] ||= {
          customer:     User.lookup(id: ticket.customer_id).attributes,
          organization: Organization.lookup(id: ticket.organization_id)&.attributes,
          time_unit:    0,
        }
        memo[ticket.customer_id][ticket.organization_id][:time_unit] += local_time_unit[:time_unit]
      end
      .values
      .map(&:values)
      .flatten

    if params[:download]
      header = [
        {
          name:  __('Customer'),
          width: 30,
        },
        {
          name:  __('Organization'),
          width: 30,
        },
        {
          name:      __('Time Units'),
          width:     10,
          data_type: 'float'
        }
      ]
      records = results.map do |row|
        customer_name = User.find(row[:customer]['id']).fullname
        organization_name = ''
        if row[:organization].present?
          organization_name = row[:organization]['name']
        end
        [customer_name, organization_name, row[:time_unit]]
      end

      excel = ExcelSheet.new(
        title:    "By Customer #{year}-#{month}",
        header:   header,
        records:  records,
        timezone: params[:timezone],
        locale:   current_user.locale,
      )
      send_data(
        excel.content,
        filename:    "by_customer-#{year}-#{month}.xlsx",
        type:        ExcelSheet::CONTENT_TYPE,
        disposition: 'attachment'
      )
      return
    end

    results = results.last(params[:limit].to_i) if params[:limit]
    render json: results
  end

  def by_organization
    year  = params[:year] || Time.zone.now.year
    month = params[:month] || Time.zone.now.month

    start_period = Time.zone.parse("#{year}-#{month}-01")
    end_period   = start_period.end_of_month

    results = Ticket::TimeAccounting
      .where(created_at: (start_period..end_period))
      .pluck(:ticket_id, :time_unit, :created_by_id)
      .each_with_object({}) do |record, memo|
        memo[record[0]] ||= {
          time_unit: 0,
          agent_id:  record[2],
        }
        memo[record[0]][:time_unit] += record[1]
      end
      .each_with_object({}) do |(ticket_id, local_time_unit), memo|
        ticket = Ticket.lookup(id: ticket_id)
        next if !ticket
        next if !ticket.organization_id

        memo[ticket.organization_id] ||= {
          organization: Organization.lookup(id: ticket.organization_id).attributes,
          time_unit:    0,
        }
        memo[ticket.organization_id][:time_unit] += local_time_unit[:time_unit]
      end
      .values

    if params[:download]
      header = [
        {
          name:  __('Organization'),
          width: 40,
        },
        {
          name:      __('Time Units'),
          width:     20,
          data_type: 'float',
        }
      ]

      records = results.map do |row|
        organization_name = ''
        if row[:organization].present?
          organization_name = row[:organization]['name']
        end
        [organization_name, row[:time_unit]]
      end

      excel = ExcelSheet.new(
        title:    "By Organization #{year}-#{month}",
        header:   header,
        records:  records,
        timezone: params[:timezone],
        locale:   current_user.locale,
      )
      send_data(
        excel.content,
        filename:    "by_organization-#{year}-#{month}.xlsx",
        type:        ExcelSheet::CONTENT_TYPE,
        disposition: 'attachment'
      )
      return
    end

    results = results.last(params[:limit].to_i) if params[:limit]
    render json: results
  end

  private

  def ticket_time_accounting_scope
    @ticket_time_accounting_scope ||= begin
      if params[:ticket_id]
        Ticket::TimeAccounting.where(ticket_id: params[:ticket_id])
      else
        Ticket::TimeAccounting
      end
    end
  end
end