# frozen_string_literal: true

require 'rails_helper'

RSpec.describe WeaponImportService, type: :service do
  let(:user) { create(:user) }

  # Create weapons with specific granblue_ids matching the game data
  let(:standard_weapon) do
    Weapon.find_by(granblue_id: '1040020000') ||
      create(:weapon, granblue_id: '1040020000', name_en: 'Luminiera Sword Omega')
  end

  let(:transcendable_weapon) do
    Weapon.find_by(granblue_id: '1040310600') ||
      create(:weapon, :transcendable, granblue_id: '1040310600', name_en: 'Yggdrasil Crystal Blade Omega')
  end

  let(:awakened_weapon) do
    Weapon.find_by(granblue_id: '1040914400') ||
      create(:weapon, granblue_id: '1040914400', name_en: 'Yamato Katana')
  end

  let(:ax_weapon) do
    Weapon.find_by(granblue_id: '1040213900') ||
      create(:weapon, :ax_weapon, granblue_id: '1040213900', name_en: 'Celeste Claw Omega')
  end

  # Create weapon awakenings
  let!(:awakening_atk) do
    Awakening.find_by(slug: 'weapon-atk', object_type: 'Weapon') ||
      create(:awakening, :for_weapon, slug: 'weapon-atk', name_en: 'Attack')
  end

  let!(:awakening_def) do
    Awakening.find_by(slug: 'weapon-def', object_type: 'Weapon') ||
      create(:awakening, :for_weapon, slug: 'weapon-def', name_en: 'Defense')
  end

  let!(:awakening_special) do
    Awakening.find_by(slug: 'weapon-special', object_type: 'Weapon') ||
      create(:awakening, :for_weapon, slug: 'weapon-special', name_en: 'Special')
  end

  let!(:awakening_ca) do
    Awakening.find_by(slug: 'weapon-ca', object_type: 'Weapon') ||
      create(:awakening, :for_weapon, slug: 'weapon-ca', name_en: 'C.A.')
  end

  let!(:awakening_skill) do
    Awakening.find_by(slug: 'weapon-skill', object_type: 'Weapon') ||
      create(:awakening, :for_weapon, slug: 'weapon-skill', name_en: 'Skill DMG')
  end

  let!(:awakening_heal) do
    Awakening.find_by(slug: 'weapon-heal', object_type: 'Weapon') ||
      create(:awakening, :for_weapon, slug: 'weapon-heal', name_en: 'Healing')
  end

  # Create weapon stat modifiers for AX skill tests
  let!(:ax_atk_modifier) do
    WeaponStatModifier.find_by(slug: 'ax_atk') ||
      create(:weapon_stat_modifier, :ax_atk)
  end

  let!(:ax_hp_modifier) do
    WeaponStatModifier.find_by(slug: 'ax_hp') ||
      create(:weapon_stat_modifier, :ax_hp)
  end

  let!(:ax_ca_dmg_modifier) do
    WeaponStatModifier.find_by(slug: 'ax_ca_dmg') ||
      create(:weapon_stat_modifier,
             slug: 'ax_ca_dmg',
             name_en: 'C.A. DMG',
             category: 'ax',
             stat: 'ca_dmg',
             polarity: 1,
             suffix: '%',
             game_skill_id: 1591)
  end

  before do
    standard_weapon
    transcendable_weapon
    awakened_weapon
    ax_weapon
  end

  describe '#import' do
    context 'with valid game data' do
      let(:game_data) do
        {
          'list' => [
            {
              'param' => {
                'id' => '49858531',
                'image_id' => '1040020000',
                'evolution' => 3,
                'phase' => 0
              },
              'master' => {
                'id' => '1040020000',
                'name' => 'Luminiera Sword Omega'
              }
            }
          ]
        }
      end

      it 'creates a collection weapon' do
        service = described_class.new(user, game_data)
        result = service.import

        expect(result.success?).to be true
        expect(result.created.size).to eq(1)
        expect(result.errors).to be_empty
      end

      it 'sets the correct game_id' do
        service = described_class.new(user, game_data)
        result = service.import

        weapon = result.created.first
        expect(weapon.game_id).to eq('49858531')
      end

      it 'sets the correct uncap_level from evolution' do
        service = described_class.new(user, game_data)
        result = service.import

        weapon = result.created.first
        expect(weapon.uncap_level).to eq(3)
      end

      it 'associates the correct weapon via granblue_id' do
        service = described_class.new(user, game_data)
        result = service.import

        weapon = result.created.first
        expect(weapon.weapon.granblue_id).to eq('1040020000')
      end
    end

    context 'with transcendence data' do
      let(:game_data) do
        {
          'list' => [
            {
              'param' => {
                'id' => '53169135',
                'image_id' => '1040310600',
                'evolution' => 5,
                'phase' => 6
              },
              'master' => {
                'id' => '1040310600',
                'name' => 'Yggdrasil Crystal Blade Omega'
              }
            }
          ]
        }
      end

      it 'sets transcendence_step from phase' do
        service = described_class.new(user, game_data)
        result = service.import

        weapon = result.created.first
        expect(weapon.transcendence_step).to eq(6)
      end

      it 'sets uncap_level to 5 for transcended weapons' do
        service = described_class.new(user, game_data)
        result = service.import

        weapon = result.created.first
        expect(weapon.uncap_level).to eq(5)
      end
    end

    context 'with awakening data' do
      let(:game_data) do
        {
          'list' => [
            {
              'param' => {
                'id' => '96548732',
                'image_id' => '1040914400',
                'evolution' => 5,
                'phase' => 0,
                'arousal' => {
                  'is_arousal_weapon' => true,
                  'level' => 15,
                  'form' => 1,
                  'form_name' => 'Attack'
                }
              },
              'master' => {
                'id' => '1040914400',
                'name' => 'Yamato Katana'
              }
            }
          ]
        }
      end

      it 'sets awakening_id based on form' do
        service = described_class.new(user, game_data)
        result = service.import

        weapon = result.created.first
        expect(weapon.awakening).to eq(awakening_atk)
      end

      it 'sets awakening_level from arousal level' do
        service = described_class.new(user, game_data)
        result = service.import

        weapon = result.created.first
        expect(weapon.awakening_level).to eq(15)
      end
    end

    context 'with different awakening forms' do
      {
        1 => 'weapon-atk',
        2 => 'weapon-def',
        3 => 'weapon-special',
        4 => 'weapon-ca',
        5 => 'weapon-skill',
        6 => 'weapon-heal'
      }.each do |form, slug|
        it "maps awakening form #{form} to #{slug}" do
          game_data = {
            'list' => [
              {
                'param' => {
                  'id' => "test_#{form}",
                  'image_id' => '1040914400',
                  'evolution' => 5,
                  'phase' => 0,
                  'arousal' => {
                    'is_arousal_weapon' => true,
                    'level' => 10,
                    'form' => form
                  }
                },
                'master' => { 'id' => '1040914400' }
              }
            ]
          }

          service = described_class.new(user, game_data)
          result = service.import

          expect(result.created.first.awakening.slug).to eq(slug)
        end
      end
    end

    context 'with no awakening' do
      let(:game_data) do
        {
          'list' => [
            {
              'param' => {
                'id' => '12345678',
                'image_id' => '1040020000',
                'evolution' => 3,
                'phase' => 0,
                'arousal' => {
                  'is_arousal_weapon' => false
                }
              },
              'master' => { 'id' => '1040020000' }
            }
          ]
        }
      end

      it 'does not set awakening when is_arousal_weapon is false' do
        service = described_class.new(user, game_data)
        result = service.import

        weapon = result.created.first
        expect(weapon.awakening).to be_nil
        expect(weapon.awakening_level).to eq(1) # default value
      end
    end

    context 'with AX skills' do
      let(:game_data) do
        {
          'list' => [
            {
              'param' => {
                'id' => '55555555',
                'image_id' => '1040213900',
                'evolution' => 5,
                'phase' => 0,
                'augment_skill_info' => [
                  [
                    {
                      'skill_id' => 1589,  # ATK modifier
                      'effect_value' => '7',
                      'show_value' => '7%'
                    },
                    {
                      'skill_id' => 1588,  # HP modifier
                      'effect_value' => '2_4',
                      'show_value' => '4%'
                    }
                  ]
                ]
              },
              'master' => { 'id' => '1040213900' }
            }
          ]
        }
      end

      it 'parses first AX skill correctly' do
        service = described_class.new(user, game_data)
        result = service.import

        weapon = result.created.first
        expect(weapon.ax_modifier1).to eq(ax_atk_modifier)
        expect(weapon.ax_strength1).to eq(7.0)
      end

      it 'parses second AX skill with underscore format' do
        service = described_class.new(user, game_data)
        result = service.import

        weapon = result.created.first
        expect(weapon.ax_modifier2).to eq(ax_hp_modifier)
        expect(weapon.ax_strength2).to eq(4.0)
      end
    end

    context 'with show_value format for AX strength' do
      let(:game_data) do
        {
          'list' => [
            {
              'param' => {
                'id' => '66666666',
                'image_id' => '1040213900',
                'evolution' => 5,
                'phase' => 0,
                'augment_skill_info' => [
                  [
                    {
                      'skill_id' => 1591,  # C.A. DMG modifier
                      'effect_value' => nil,
                      'show_value' => '5.5%'
                    }
                  ]
                ]
              },
              'master' => { 'id' => '1040213900' }
            }
          ]
        }
      end

      it 'parses strength from show_value when effect_value is nil' do
        service = described_class.new(user, game_data)
        result = service.import

        weapon = result.created.first
        expect(weapon.ax_modifier1).to eq(ax_ca_dmg_modifier)
        expect(weapon.ax_strength1).to eq(5.5)
      end
    end

    context 'with duplicate game_id' do
      let(:game_data) do
        {
          'list' => [
            {
              'param' => {
                'id' => '99999999',
                'image_id' => '1040020000',
                'evolution' => 3,
                'phase' => 0
              },
              'master' => { 'id' => '1040020000' }
            }
          ]
        }
      end

      before do
        create(:collection_weapon, user: user, weapon: standard_weapon, game_id: '99999999')
      end

      it 'skips the duplicate' do
        service = described_class.new(user, game_data)
        result = service.import

        expect(result.success?).to be true
        expect(result.created.size).to eq(0)
        expect(result.skipped.size).to eq(1)
        expect(result.skipped.first[:reason]).to eq('Already exists')
      end

      context 'with update_existing: true' do
        let(:game_data_updated) do
          {
            'list' => [
              {
                'param' => {
                  'id' => '99999999',
                  'image_id' => '1040020000',
                  'evolution' => 5,
                  'phase' => 0
                },
                'master' => { 'id' => '1040020000' }
              }
            ]
          }
        end

        it 'updates the existing weapon' do
          service = described_class.new(user, game_data_updated, update_existing: true)
          result = service.import

          expect(result.success?).to be true
          expect(result.created.size).to eq(0)
          expect(result.updated.size).to eq(1)
          expect(result.updated.first.uncap_level).to eq(5)
        end
      end
    end

    context 'with unknown weapon' do
      let(:game_data) do
        {
          'list' => [
            {
              'param' => {
                'id' => '12345',
                'image_id' => '9999999999',
                'evolution' => 3,
                'phase' => 0
              },
              'master' => { 'id' => '9999999999' }
            }
          ]
        }
      end

      it 'records an error for the unknown weapon' do
        service = described_class.new(user, game_data)
        result = service.import

        expect(result.errors.size).to eq(1)
        expect(result.errors.first[:error]).to eq('Weapon not found')
      end
    end

    context 'with multiple weapons' do
      let(:game_data) do
        {
          'list' => [
            {
              'param' => {
                'id' => '11111111',
                'image_id' => '1040020000',
                'evolution' => 3,
                'phase' => 0
              },
              'master' => { 'id' => '1040020000' }
            },
            {
              'param' => {
                'id' => '22222222',
                'image_id' => '1040310600',
                'evolution' => 5,
                'phase' => 3
              },
              'master' => { 'id' => '1040310600' }
            }
          ]
        }
      end

      it 'imports all weapons' do
        service = described_class.new(user, game_data)
        result = service.import

        expect(result.success?).to be true
        expect(result.created.size).to eq(2)
      end

      it 'associates correct weapons' do
        service = described_class.new(user, game_data)
        result = service.import

        weapons = result.created.sort_by(&:game_id)
        expect(weapons[0].weapon.granblue_id).to eq('1040020000')
        expect(weapons[1].weapon.granblue_id).to eq('1040310600')
      end
    end

    context 'with empty data' do
      let(:game_data) { { 'list' => [] } }

      it 'returns an error' do
        service = described_class.new(user, game_data)
        result = service.import

        expect(result.success?).to be false
        expect(result.errors).to include('No weapon items found in data')
      end
    end

    context 'with array format data' do
      let(:game_data) do
        [
          {
            'param' => {
              'id' => '77777777',
              'image_id' => '1040020000',
              'evolution' => 4,
              'phase' => 0
            },
            'master' => { 'id' => '1040020000' }
          }
        ]
      end

      it 'handles array format correctly' do
        service = described_class.new(user, game_data)
        result = service.import

        expect(result.success?).to be true
        expect(result.created.size).to eq(1)
        expect(result.created.first.uncap_level).to eq(4)
      end
    end

    context 'with max uncap/transcendence values' do
      let(:game_data) do
        {
          'list' => [
            {
              'param' => {
                'id' => '88888888',
                'image_id' => '1040310600',
                'evolution' => 10,
                'phase' => 15
              },
              'master' => { 'id' => '1040310600' }
            }
          ]
        }
      end

      it 'clamps uncap_level to max 5' do
        service = described_class.new(user, game_data)
        result = service.import

        weapon = result.created.first
        expect(weapon.uncap_level).to eq(5)
      end

      it 'clamps transcendence_step to max 10' do
        service = described_class.new(user, game_data)
        result = service.import

        weapon = result.created.first
        expect(weapon.transcendence_step).to eq(10)
      end
    end

    context 'with max awakening level' do
      let(:game_data) do
        {
          'list' => [
            {
              'param' => {
                'id' => '10101010',
                'image_id' => '1040914400',
                'evolution' => 5,
                'phase' => 0,
                'arousal' => {
                  'is_arousal_weapon' => true,
                  'level' => 25,
                  'form' => 1
                }
              },
              'master' => { 'id' => '1040914400' }
            }
          ]
        }
      end

      it 'clamps awakening_level to max 20' do
        service = described_class.new(user, game_data)
        result = service.import

        weapon = result.created.first
        expect(weapon.awakening_level).to eq(20)
      end
    end

    context 'with image_id from master.id fallback' do
      let(:game_data) do
        {
          'list' => [
            {
              'param' => {
                'id' => '33333333',
                'evolution' => 3,
                'phase' => 0
              },
              'master' => {
                'id' => '1040020000'
              }
            }
          ]
        }
      end

      it 'uses master.id when param.image_id is missing' do
        service = described_class.new(user, game_data)
        result = service.import

        expect(result.success?).to be true
        expect(result.created.first.weapon.granblue_id).to eq('1040020000')
      end
    end
  end

  describe 'edge cases' do
    context 'with nil arousal' do
      let(:game_data) do
        {
          'list' => [
            {
              'param' => {
                'id' => '44444444',
                'image_id' => '1040020000',
                'evolution' => 3,
                'phase' => 0,
                'arousal' => nil
              },
              'master' => { 'id' => '1040020000' }
            }
          ]
        }
      end

      it 'handles nil arousal gracefully' do
        service = described_class.new(user, game_data)
        result = service.import

        expect(result.success?).to be true
        expect(result.created.first.awakening).to be_nil
      end
    end

    context 'with empty augment_skill_info' do
      let(:game_data) do
        {
          'list' => [
            {
              'param' => {
                'id' => '55556666',
                'image_id' => '1040213900',
                'evolution' => 5,
                'phase' => 0,
                'augment_skill_info' => []
              },
              'master' => { 'id' => '1040213900' }
            }
          ]
        }
      end

      it 'handles empty augment_skill_info gracefully' do
        service = described_class.new(user, game_data)
        result = service.import

        expect(result.success?).to be true
        expect(result.created.first.ax_modifier1).to be_nil
        expect(result.created.first.ax_modifier2).to be_nil
      end
    end
  end
end
