# frozen_string_literal: true

class <%= class_name %>ItemsController < ApplicationController
  ALLOWED_ACCOUNTABLE_TYPES = %w[Depository CreditCard Investment Loan OtherAsset OtherLiability Crypto Property Vehicle].freeze

  before_action :set_<%= file_name %>_item, only: [ :show, :edit, :update, :destroy, :sync, :setup_accounts, :complete_account_setup ]

  def index
    @<%= table_name %> = Current.family.<%= table_name %>.ordered
  end

  def show
  end

  def new
    @<%= file_name %>_item = Current.family.<%= table_name %>.build
  end

  def edit
  end

  def create
    @<%= file_name %>_item = Current.family.<%= table_name %>.build(<%= file_name %>_item_params)
    @<%= file_name %>_item.name ||= "<%= class_name %> Connection"

    if @<%= file_name %>_item.save
      if turbo_frame_request?
        flash.now[:notice] = t(".success", default: "Successfully configured <%= class_name %>.")
        @<%= table_name %> = Current.family.<%= table_name %>.ordered
        render turbo_stream: [
          turbo_stream.replace(
            "<%= file_name %>-providers-panel",
            partial: "settings/providers/<%= file_name %>_panel",
            locals: { <%= file_name %>_items: @<%= table_name %> }
          ),
          *flash_notification_stream_items
        ]
      else
        redirect_to settings_providers_path, notice: t(".success"), status: :see_other
      end
    else
      @error_message = @<%= file_name %>_item.errors.full_messages.join(", ")

      if turbo_frame_request?
        render turbo_stream: turbo_stream.replace(
          "<%= file_name %>-providers-panel",
          partial: "settings/providers/<%= file_name %>_panel",
          locals: { error_message: @error_message }
        ), status: :unprocessable_entity
      else
        redirect_to settings_providers_path, alert: @error_message, status: :unprocessable_entity
      end
    end
  end

  def update
    if @<%= file_name %>_item.update(<%= file_name %>_item_params)
      if turbo_frame_request?
        flash.now[:notice] = t(".success", default: "Successfully updated <%= class_name %> configuration.")
        @<%= table_name %> = Current.family.<%= table_name %>.ordered
        render turbo_stream: [
          turbo_stream.replace(
            "<%= file_name %>-providers-panel",
            partial: "settings/providers/<%= file_name %>_panel",
            locals: { <%= file_name %>_items: @<%= table_name %> }
          ),
          *flash_notification_stream_items
        ]
      else
        redirect_to settings_providers_path, notice: t(".success"), status: :see_other
      end
    else
      @error_message = @<%= file_name %>_item.errors.full_messages.join(", ")

      if turbo_frame_request?
        render turbo_stream: turbo_stream.replace(
          "<%= file_name %>-providers-panel",
          partial: "settings/providers/<%= file_name %>_panel",
          locals: { error_message: @error_message }
        ), status: :unprocessable_entity
      else
        redirect_to settings_providers_path, alert: @error_message, status: :unprocessable_entity
      end
    end
  end

  def destroy
    @<%= file_name %>_item.destroy_later
    redirect_to settings_providers_path, notice: t(".success", default: "Scheduled <%= class_name %> connection for deletion.")
  end

  def sync
    unless @<%= file_name %>_item.syncing?
      @<%= file_name %>_item.sync_later
    end

    respond_to do |format|
      format.html { redirect_back_or_to accounts_path }
      format.json { head :ok }
    end
  end

  # Collection actions for account linking flow

  def preload_accounts
    # Trigger a sync to fetch accounts from the provider
    <%= file_name %>_item = Current.family.<%= file_name %>_items.first
    unless <%= file_name %>_item&.credentials_configured?
      redirect_to settings_providers_path, alert: t(".no_credentials_configured")
      return
    end

    <%= file_name %>_item.sync_later unless <%= file_name %>_item.syncing?
    redirect_to select_accounts_<%= file_name %>_items_path(accountable_type: params[:accountable_type], return_to: params[:return_to])
  end

  def select_accounts
    @accountable_type = params[:accountable_type]
    @return_to = params[:return_to]

    <%= file_name %>_item = Current.family.<%= file_name %>_items.first
    unless <%= file_name %>_item&.credentials_configured?
      redirect_to settings_providers_path, alert: t(".no_credentials_configured")
      return
    end

    @<%= file_name %>_accounts = <%= file_name %>_item.<%= file_name %>_accounts
                                                .left_joins(:account_provider)
                                                .where(account_providers: { id: nil })
                                                .order(:name)
  end

  def link_accounts
    <%= file_name %>_item = Current.family.<%= file_name %>_items.first
    unless <%= file_name %>_item&.credentials_configured?
      redirect_to settings_providers_path, alert: t(".no_api_key")
      return
    end

    selected_ids = params[:selected_account_ids] || []
    if selected_ids.empty?
      redirect_to select_accounts_<%= file_name %>_items_path, alert: t(".no_accounts_selected")
      return
    end

    accountable_type = params[:accountable_type] || "Depository"
    created_count = 0
    already_linked_count = 0
    invalid_count = 0

    <%= file_name %>_item.<%= file_name %>_accounts.where(id: selected_ids).find_each do |<%= file_name %>_account|
      # Skip if already linked
      if <%= file_name %>_account.account_provider.present?
        already_linked_count += 1
        next
      end

      # Skip if invalid name
      if <%= file_name %>_account.name.blank?
        invalid_count += 1
        next
      end

      # Create Sure account and link
      link_<%= file_name %>_account(<%= file_name %>_account, accountable_type)
      created_count += 1
    rescue => e
      Rails.logger.error "<%= class_name %>ItemsController#link_accounts - Failed to link account: #{e.message}"
    end

    if created_count > 0
      <%= file_name %>_item.sync_later unless <%= file_name %>_item.syncing?
      redirect_to accounts_path, notice: t(".success", count: created_count)
    else
      redirect_to select_accounts_<%= file_name %>_items_path, alert: t(".link_failed")
    end
  end

  def select_existing_account
    @account = Current.family.accounts.find(params[:account_id])
    @<%= file_name %>_item = Current.family.<%= file_name %>_items.first

    unless @<%= file_name %>_item&.credentials_configured?
      redirect_to settings_providers_path, alert: t(".no_credentials_configured")
      return
    end

    @<%= file_name %>_accounts = @<%= file_name %>_item.<%= file_name %>_accounts
                                                      .left_joins(:account_provider)
                                                      .where(account_providers: { id: nil })
                                                      .order(:name)
  end

  def link_existing_account
    account = Current.family.accounts.find(params[:account_id])
    <%= file_name %>_item = Current.family.<%= file_name %>_items.first

    unless <%= file_name %>_item&.credentials_configured?
      redirect_to settings_providers_path, alert: t(".no_api_key")
      return
    end

    <%= file_name %>_account = <%= file_name %>_item.<%= file_name %>_accounts.find(params[:<%= file_name %>_account_id])

    if <%= file_name %>_account.account_provider.present?
      redirect_to account_path(account), alert: t(".provider_account_already_linked")
      return
    end

    <%= file_name %>_account.ensure_account_provider!(account)
    <%= file_name %>_item.sync_later unless <%= file_name %>_item.syncing?

    redirect_to account_path(account), notice: t(".success", account_name: account.name)
  end

  def setup_accounts
    @unlinked_accounts = @<%= file_name %>_item.unlinked_<%= file_name %>_accounts.order(:name)

    if @unlinked_accounts.empty?
      redirect_to accounts_path, notice: t(".all_accounts_linked")
    end
  end

  def complete_account_setup
    account_configs = params[:accounts] || {}

    if account_configs.empty?
      redirect_to setup_accounts_<%= file_name %>_item_path(@<%= file_name %>_item), alert: t(".no_accounts")
      return
    end

    created_count = 0
    skipped_count = 0

    account_configs.each do |<%= file_name %>_account_id, config|
      next if config[:account_type] == "skip"

      <%= file_name %>_account = @<%= file_name %>_item.<%= file_name %>_accounts.find_by(id: <%= file_name %>_account_id)
      next unless <%= file_name %>_account
      next if <%= file_name %>_account.account_provider.present?

      accountable_type = infer_accountable_type(config[:account_type], config[:subtype])
      account = create_account_from_<%= file_name %>(<%= file_name %>_account, accountable_type, config)

      if account&.persisted?
        <%= file_name %>_account.ensure_account_provider!(account)
        <%= file_name %>_account.update!(sync_start_date: config[:sync_start_date]) if config[:sync_start_date].present?
        created_count += 1
      else
        skipped_count += 1
      end
    rescue => e
      Rails.logger.error "<%= class_name %>ItemsController#complete_account_setup - Error: #{e.message}"
      skipped_count += 1
    end

    if created_count > 0
      @<%= file_name %>_item.sync_later unless @<%= file_name %>_item.syncing?
      redirect_to accounts_path, notice: t(".success", count: created_count)
    elsif skipped_count > 0 && created_count == 0
      redirect_to accounts_path, notice: t(".all_skipped")
    else
      redirect_to setup_accounts_<%= file_name %>_item_path(@<%= file_name %>_item), alert: t(".creation_failed", error: "Unknown error")
    end
  end

  private

    def set_<%= file_name %>_item
      @<%= file_name %>_item = Current.family.<%= table_name %>.find(params[:id])
    end

    def <%= file_name %>_item_params
      params.require(:<%= file_name %>_item).permit(
        :name,
        :sync_start_date<% parsed_fields.each do |field| %>,
        :<%= field[:name] %><% end %>
      )
    end

    def link_<%= file_name %>_account(<%= file_name %>_account, accountable_type)
      accountable_class = validated_accountable_class(accountable_type)

      account = Current.family.accounts.create!(
        name: <%= file_name %>_account.name,
        balance: <%= file_name %>_account.current_balance || 0,
        currency: <%= file_name %>_account.currency || "USD",
        accountable: accountable_class.new
      )

      <%= file_name %>_account.ensure_account_provider!(account)
      account
    end

    def create_account_from_<%= file_name %>(<%= file_name %>_account, accountable_type, config)
      accountable_class = validated_accountable_class(accountable_type)
      accountable_attrs = {}

      # Set subtype if the accountable supports it
      if config[:subtype].present? && accountable_class.respond_to?(:subtypes)
        accountable_attrs[:subtype] = config[:subtype]
      end

      Current.family.accounts.create!(
        name: <%= file_name %>_account.name,
        balance: config[:balance].present? ? config[:balance].to_d : (<%= file_name %>_account.current_balance || 0),
        currency: <%= file_name %>_account.currency || "USD",
        accountable: accountable_class.new(accountable_attrs)
      )
    end

    def infer_accountable_type(account_type, subtype = nil)
      case account_type&.downcase
      when "depository"
        "Depository"
      when "credit_card"
        "CreditCard"
      when "investment"
        "Investment"
      when "loan"
        "Loan"
      when "other_asset"
        "OtherAsset"
      when "other_liability"
        "OtherLiability"
      when "crypto"
        "Crypto"
      when "property"
        "Property"
      when "vehicle"
        "Vehicle"
      else
        "Depository"
      end
    end

    def validated_accountable_class(accountable_type)
      unless ALLOWED_ACCOUNTABLE_TYPES.include?(accountable_type)
        raise ArgumentError, "Invalid accountable type: #{accountable_type}"
      end

      accountable_type.constantize
    end
end
