module Validations::Sales::SoftValidations
  include Validations::Sales::SaleInformationValidations

  ALLOWED_INCOME_RANGES_SALES = {
    2024 => {
      1 => OpenStruct.new(soft_min: 5000),
      2 => OpenStruct.new(soft_min: 1500),
      3 => OpenStruct.new(soft_min: 1000),
      5 => OpenStruct.new(soft_min: 2000),
      0 => OpenStruct.new(soft_min: 2000),
    },
    2025 => {
      1 => OpenStruct.new(soft_min: 13_400, soft_max: 150_000),
      2 => OpenStruct.new(soft_min: 2_600, soft_max: 80_000),
      3 => OpenStruct.new(soft_min: 2_080, soft_max: 30_000),
      4 => OpenStruct.new(soft_min: 520, soft_max: 23_400),
      5 => OpenStruct.new(soft_min: 520, soft_max: 80_000),
      6 => OpenStruct.new(soft_min: 520, soft_max: 50_000),
      7 => OpenStruct.new(soft_min: 520, soft_max: 30_000),
      8 => OpenStruct.new(soft_min: 520, soft_max: 150_000),
      9 => OpenStruct.new(soft_min: 520, soft_max: 150_000),
      0 => OpenStruct.new(soft_min: 520, soft_max: 150_000),
    },
  }.freeze

  def income1_outside_soft_range_for_ecstat?
    income1_under_soft_min? || income1_over_soft_max_for_ecstat?
  end

  def income1_more_or_less_text
    income1_under_soft_min? ? "less" : "more"
  end

  def income2_outside_soft_range_for_ecstat?
    income2_under_soft_min? || income2_over_soft_max_for_ecstat?
  end

  def income2_more_or_less_text
    income2_under_soft_min? ? "less" : "more"
  end

  def income1_over_soft_max_for_discounted_ownership?
    return unless income1 && la && discounted_ownership_sale?

    income_over_discounted_sale_soft_max?(income1)
  end

  def income2_over_soft_max_for_discounted_ownership?
    return unless income2 && la && discounted_ownership_sale?

    income_over_discounted_sale_soft_max?(income2)
  end

  def combined_income_over_soft_max_for_discounted_ownership?
    return unless income1 && income2 && la && discounted_ownership_sale?

    income_over_discounted_sale_soft_max?(income1 + income2)
  end

  def staircase_bought_above_fifty?
    stairbought && stairbought > 50
  end

  def mortgage_over_soft_max?
    return false unless mortgage && inc1mort && (inc2mort || not_joint_purchase?)
    return false if income1_used_for_mortgage? && income1.blank? || income2_used_for_mortgage? && income2.blank?

    income_used_for_mortgage = (income1_used_for_mortgage? ? income1 : 0) + (income2_used_for_mortgage? ? income2 : 0)
    mortgage > income_used_for_mortgage * 5
  end

  def wheelchair_when_not_disabled?
    return unless disabled && wheel

    wheel == 1 && disabled == 2
  end

  def savings_over_soft_max?
    soft_max = form.start_year_2025_or_later? && type == 24 ? 200_000 : 100_000

    savings && savings > soft_max
  end

  def deposit_over_soft_max?
    return unless savings && deposit && mortgage_used?

    deposit > savings * 4 / 3
  end

  def extra_borrowing_expected_but_not_reported?
    return unless saledate && !form.start_year_2024_or_later?
    return unless extrabor && mortgage && deposit && value && discount

    extrabor != 1 && mortgage + deposit > value - value * discount / 100
  end

  def purchase_price_out_of_soft_range?
    return unless value && beds && la && sale_range

    !value.between?(sale_range.soft_min, sale_range.soft_max)
  end

  def staircase_owned_out_of_soft_range?
    return unless type && stairowned

    type == 24 && stairowned.between?(76, 100)
  end

  def shared_ownership_deposit_invalid?
    return unless saledate && collection_start_year <= 2023
    return unless mortgage || mortgageused == 2 || mortgageused == 3
    return unless cashdis || !social_homebuy?
    return unless deposit && value && equity

    over_tolerance?(mortgage_deposit_and_discount_total, value * equity / 100, 1)
  end

  def mortgage_plus_deposit_less_than_discounted_value?
    return unless mortgage && deposit && value && discount

    discounted_value = value * (100 - discount) / 100
    mortgage + deposit < discounted_value
  end

  def hodate_3_years_or_more_saledate?
    return unless hodate && saledate

    saledate - hodate >= 3.years
  end

  def hodate_5_years_or_more_saledate?
    return unless hodate && saledate

    saledate - hodate >= 5.years
  end

  def purchase_price_higher_or_lower_text
    value < sale_range.soft_min ? "lower" : "higher"
  end

  def purchase_price_soft_min_or_soft_max
    value < sale_range.soft_min ? sale_range.soft_min : sale_range.soft_max
  end

  def grant_outside_common_range?
    return unless grant && type && saledate
    return if form.start_year_2024_or_later? && (type == 21 || type == 8)

    !grant.between?(9_000, 16_000)
  end

  def monthly_charges_over_soft_max?
    return unless type && mscharge && proptype

    soft_max = old_persons_shared_ownership? ? 550 : 300
    mscharge > soft_max
  end

  (2..6).each do |person_num|
    define_method("person_#{person_num}_student_not_child?") do
      relat = send("relat#{person_num}")
      ecstat = send("ecstat#{person_num}")
      age = send("age#{person_num}")
      return unless age && ecstat && relat

      age.between?(16, 19) && ecstat == 7 && relat != "C"
    end
  end

  def discounted_ownership_value_invalid?
    return unless saledate && collection_start_year <= 2023
    return unless value && deposit && ownershipsch
    return unless mortgage || mortgageused == 2 || mortgageused == 3
    return unless discount || grant || type == 29

    mortgage_deposit_and_grant_total != value_with_discount && discounted_ownership_sale?
  end

  def buyer1_livein_wrong_for_ownership_type?
    return unless ownershipsch && buy1livein

    (discounted_ownership_sale? || shared_ownership_scheme?) && buy1livein == 2
  end

  def buyer2_livein_wrong_for_ownership_type?
    return unless ownershipsch && buy2livein
    return unless joint_purchase?

    (discounted_ownership_sale? || shared_ownership_scheme?) && buy2livein == 2
  end

  def percentage_discount_invalid?
    return unless discount && proptype

    case proptype
    when 1, 2
      discount > 50
    when 3, 4, 9
      discount > 35
    end
  end

private

  def sale_range
    LaSaleRange.find_by(
      start_year: collection_start_year,
      la:,
      bedrooms: beds_for_la_sale_range,
    )
  end

  def income1_under_soft_min?
    income_under_soft_min?(income1, ecstat1)
  end

  def income2_under_soft_min?
    income_under_soft_min?(income2, ecstat2)
  end

  def income_under_soft_min?(income, ecstat)
    return unless income && ecstat

    income_ranges = form.start_year_2025_or_later? ? ALLOWED_INCOME_RANGES_SALES[2025] : ALLOWED_INCOME_RANGES_SALES[2024]
    return false unless income_ranges[ecstat]

    income < income_ranges[ecstat][:soft_min]
  end

  def income1_over_soft_max_for_ecstat?
    income_over_soft_max?(income1, ecstat1)
  end

  def income2_over_soft_max_for_ecstat?
    income_over_soft_max?(income2, ecstat2)
  end

  def income_over_soft_max?(income, ecstat)
    return unless income && ecstat && form.start_year_2025_or_later?

    return false unless ALLOWED_INCOME_RANGES_SALES[2025][ecstat]

    income > ALLOWED_INCOME_RANGES_SALES[2025][ecstat][:soft_max]
  end

  def income_over_discounted_sale_soft_max?(income)
    (london_property? && income > 90_000) || (property_not_in_london? && income > 80_000)
  end
end