class Captain::Reservations::CreateService
  def initialize(account:, params:, created_by: nil)
    @account = account
    @params = params
    @created_by = created_by
  end

  def perform
    reservation = Captain::Reservation.create!(reservation_params)

    # Generate Pix Charge natively
    if reservation.unit&.inter_credentials_present?
      charge_result = generate_pix_charge(reservation)
      if charge_result[:success]
        reservation.metadata['pix'] = charge_result[:payload]
        reservation.save!
      else
        Rails.logger.error "Pix Generation Failed: #{charge_result[:error]}"
      end
    end

    schedule_automations(reservation)
    reservation
  end

  private

  attr_reader :account, :params, :created_by

  def reservation_params
    conversation = find_conversation
    inbox = conversation&.inbox || find_inbox
    contact_inbox = conversation&.contact_inbox || find_or_create_contact_inbox(inbox)

    raise ArgumentError, 'Inbox not found' unless inbox.present?
    raise ArgumentError, 'Contact not found' unless contact_inbox&.contact.present?

    check_in_at = parse_time(params[:check_in_at])
    raise ArgumentError, 'Check-in time is required' unless check_in_at

    check_out_at = parse_time(params[:check_out_at]) || calculate_check_out(check_in_at)

    brand = find_brand(params[:brand_id])
    unit = find_unit(params[:unit_id])

    {
      account: account,
      inbox: inbox,
      contact: contact_inbox.contact,
      contact_inbox: contact_inbox,
      conversation: conversation,
      brand: brand,
      unit: unit,
      suite_identifier: params[:suite_identifier],
      check_in_at: check_in_at,
      check_out_at: check_out_at,
      status: :pending_payment,
      payment_status: :pending,
      total_amount: params[:total_amount],
      integracao_id: params[:integracao_id] || SecureRandom.uuid,
      metadata: params[:metadata] || {},
      created_by_id: created_by&.id,
      created_by_type: created_by&.class&.name
    }
  end

  def schedule_automations(reservation)
    automations = Captain::InboxAutomation
                  .where(account: reservation.account, inbox: reservation.inbox, enabled: true)
                  .order(created_at: :asc)

    automations.each do |automation|
      scheduled_at = automation.scheduled_at(
        check_in_at: reservation.check_in_at,
        check_out_at: reservation.check_out_at
      )
      next if scheduled_at.blank?

      Captain::Reminder.create!(
        account: reservation.account,
        inbox: reservation.inbox,
        contact: reservation.contact,
        contact_inbox: reservation.contact_inbox,
        conversation: reservation.conversation,
        reminder_type: :automation,
        status: :scheduled,
        message: automation.message,
        scheduled_at: scheduled_at,
        source_type: reservation.class.name,
        source_id: reservation.id,
        metadata: {
          automation_id: automation.id,
          automation_title: automation.title
        }
      )
    end
  end

  def calculate_check_out(check_in_at)
    duration_minutes = params[:duration_minutes].to_i
    return check_in_at if duration_minutes <= 0

    check_in_at + duration_minutes.minutes
  end

  def parse_time(value)
    return if value.blank?

    Time.zone.parse(value.to_s)
  end

  def find_conversation
    return if params[:conversation_id].blank?

    account.conversations.find_by(id: params[:conversation_id])
  end

  def find_inbox
    return if params[:inbox_id].blank?

    account.inboxes.find_by(id: params[:inbox_id])
  end

  def find_or_create_contact_inbox(inbox)
    phone_number = params[:phone_number].to_s.strip
    return if phone_number.blank? || inbox.blank?

    source_id = normalized_source_id(inbox, phone_number)
    contact_attributes = {
      name: params[:contact_name],
      phone_number: normalized_phone_number(phone_number)
    }.compact

    ContactInboxWithContactBuilder.new(
      inbox: inbox,
      source_id: source_id,
      contact_attributes: contact_attributes
    ).perform
  end

  def normalized_source_id(inbox, phone_number)
    return phone_number unless inbox.channel_type == 'Channel::Whatsapp'

    Whatsapp::PhoneNumberNormalizationService.new(inbox).normalize_and_find_contact_by_provider(phone_number, :cloud)
  end

  def normalized_phone_number(phone_number)
    phone_number.start_with?('+') ? phone_number : "+#{phone_number}"
  end

  def find_brand(brand_id)
    return unless brand_id.present?

    Captain::Brand.find_by(id: brand_id, account_id: account.id)
  end

  def find_unit(unit_id)
    return unless unit_id.present?

    Captain::Unit.find_by(id: unit_id, account_id: account.id)
  end

  def generate_pix_charge(reservation)
    service = Captain::Inter::CobService.new(reservation.unit)

    # 50% of total amount as down payment, default to full amount if not specified
    amount = reservation.total_amount ? (reservation.total_amount / 2.0).round(2) : 50.00

    response = service.create_immediate_charge(
      amount: amount,
      expiration_seconds: 600, # 10 minutes
      payer: {
        cpf_cnpj: params[:cpf] || params[:cnpj],
        name: params[:contact_name] || 'Cliente'
      }
    )

    if response[:success]
      payload = response[:payload]

      # Persist Charge
      charge = Captain::PixCharge.create!(
        reservation: reservation,
        unit: reservation.unit,
        txid: payload['txid'],
        pix_copia_e_cola: payload['pixCopiaECola'],
        status: payload['status'], # ATIVA
        raw_webhook_payload: payload
      )

      reservation.update!(current_pix_charge_id: charge.id)

      {
        success: true,
        payload: {
          txid: payload['txid'],
          pixCopiaECola: payload['pixCopiaECola'],
          pixUrl: payload['loc']['location'] # Used for QR Code generation
        }
      }
    else
      { success: false, error: response[:error] }
    end
  rescue StandardError => e
    { success: false, error: e.message }
  end
end
