# frozen_string_literal: true

require 'rails_helper'

RSpec.describe SiteAdmin::Properties::SettingsController, type: :controller do
  let(:website) { create(:pwb_website, subdomain: 'test-site') }
  let(:other_website) { create(:pwb_website, subdomain: 'other-site') }
  let(:user) { create(:pwb_user, :admin, website: website) }

  before do
    Pwb::Current.reset
    @request.env['devise.mapping'] = Devise.mappings[:user]
    sign_in user, scope: :user
    allow(Pwb::Current).to receive(:website).and_return(website)
    allow(controller).to receive(:current_website).and_return(website)
    ActsAsTenant.current_tenant = website
  end

  after do
    ActsAsTenant.current_tenant = nil
  end

  describe 'GET #index' do
    it 'renders the index template' do
      get :index
      expect(response).to have_http_status(:success)
      expect(response).to render_template(:index)
    end

    it 'assigns categories' do
      get :index
      expect(assigns(:categories)).to eq(['property_types', 'property_states', 'property_features', 'property_amenities', 'property_status', 'property_highlights', 'listing_origin'])
    end
  end

  describe 'GET #show' do
    let!(:field_key1) do
      ActsAsTenant.with_tenant(website) do
        create(:pwb_field_key, tag: 'property-types', website: website, sort_order: 1)
      end
    end

    let!(:field_key2) do
      ActsAsTenant.with_tenant(website) do
        create(:pwb_field_key, tag: 'property-types', website: website, sort_order: 0)
      end
    end

    let!(:other_website_key) do
      ActsAsTenant.with_tenant(other_website) do
        create(:pwb_field_key, tag: 'property-types', website: other_website)
      end
    end

    it 'loads field keys for the specified category' do
      get :show, params: { category: 'property_types' }

      expect(response).to have_http_status(:success)
      expect(assigns(:field_keys)).to include(field_key1, field_key2)
      expect(assigns(:field_keys)).not_to include(other_website_key)
    end

    it 'orders field keys by sort_order and created_at' do
      get :show, params: { category: 'property_types' }

      field_keys = assigns(:field_keys).to_a
      expect(field_keys.first).to eq(field_key2) # sort_order 0
      expect(field_keys.last).to eq(field_key1)  # sort_order 1
    end

    it 'scopes to current website only' do
      get :show, params: { category: 'property_types' }

      expect(assigns(:field_keys).map(&:pwb_website_id)).to all(eq(website.id))
    end

    it 'redirects with alert for invalid category' do
      get :show, params: { category: 'invalid_category' }

      expect(response).to redirect_to(site_admin_root_path)
      expect(flash[:alert]).to eq('Invalid category')
    end

    it 'renders the show template' do
      get :show, params: { category: 'property_features' }
      expect(response).to render_template(:show)
    end
  end

  describe 'POST #create' do
    let(:valid_params) do
      {
        category: 'property_types',
        field_key: {
          translations: {
            en: 'Warehouse',
            es: 'Almacén',
            fr: 'Entrepôt'
          },
          visible: true,
          sort_order: 5
        }
      }
    end

    it 'creates a new field key' do
      expect {
        post :create, params: valid_params
      }.to change(Pwb::FieldKey, :count).by(1)
    end

    it 'associates field key with current website' do
      post :create, params: valid_params

      field_key = Pwb::FieldKey.last
      expect(field_key.website).to eq(website)
    end

    it 'sets the correct tag based on category' do
      post :create, params: valid_params

      field_key = Pwb::FieldKey.last
      expect(field_key.tag).to eq('property-types')
    end

    it 'generates a unique global_key' do
      post :create, params: valid_params

      field_key = Pwb::FieldKey.last
      # Format: {prefix}.{snake_case_name} or {prefix}.{snake_case_name}_{timestamp}
      expect(field_key.global_key).to match(/^types\.[a-z_]+(_\d+)?$/)
    end

    it 'sets sort_order from params' do
      post :create, params: valid_params

      field_key = Pwb::FieldKey.last
      expect(field_key.sort_order).to eq(5)
    end

    it 'redirects to show page with success notice' do
      post :create, params: valid_params

      expect(response).to redirect_to(site_admin_properties_settings_category_path('property_types'))
      expect(flash[:notice]).to eq('Setting created successfully')
    end

    it 'stores translations' do
      post :create, params: valid_params

      field_key = Pwb::FieldKey.last
      # Note: Translation storage depends on I18n backend configuration
      # This test verifies the controller calls the translation method
      expect(field_key.global_key).to be_present
    end
  end

  describe 'PATCH #update' do
    let(:field_key) do
      ActsAsTenant.with_tenant(website) do
        create(:pwb_field_key, website: website, tag: 'property-types', visible: true, sort_order: 0)
      end
    end

    let(:update_params) do
      {
        category: 'property_types',
        id: field_key.global_key,
        field_key: {
          translations: {
            en: 'Updated Name'
          },
          visible: false,
          sort_order: 10
        }
      }
    end

    it 'updates the field key attributes' do
      patch :update, params: update_params

      field_key.reload
      expect(field_key.visible).to be false
      expect(field_key.sort_order).to eq(10)
    end

    it 'redirects to show page with success notice' do
      patch :update, params: update_params

      expect(response).to redirect_to(site_admin_properties_settings_category_path('property_types'))
      expect(flash[:notice]).to eq('Setting updated successfully')
    end

    it 'redirects for field keys from other websites' do
      other_field_key = ActsAsTenant.with_tenant(other_website) do
        create(:pwb_field_key, website: other_website, tag: 'property-types')
      end

      patch :update, params: {
        category: 'property_types',
        id: other_field_key.global_key,
        field_key: { visible: false }
      }

      # Controller redirects with alert when field key not found in current tenant
      expect(response).to redirect_to(site_admin_properties_settings_category_path('property_types'))
      expect(flash[:alert]).to eq('Setting not found')
    end

    describe 'translation persistence (Mobility)' do
      it 'saves translations to the model JSONB column' do
        patch :update, params: {
          category: 'property_types',
          id: field_key.global_key,
          field_key: {
            translations: {
              en: 'Apartment Updated'
            }
          }
        }

        field_key.reload
        expect(field_key.translations).to include('en' => { 'label' => 'Apartment Updated' })
      end

      it 'persists English translation that can be retrieved via Mobility' do
        patch :update, params: {
          category: 'property_types',
          id: field_key.global_key,
          field_key: {
            translations: {
              en: 'Luxury Villa'
            }
          }
        }

        field_key.reload
        Mobility.with_locale(:en) do
          expect(field_key.label).to eq('Luxury Villa')
        end
      end

      it 'persists multiple locale translations' do
        patch :update, params: {
          category: 'property_types',
          id: field_key.global_key,
          field_key: {
            translations: {
              en: 'Apartment',
              es: 'Apartamento',
              fr: 'Appartement'
            }
          }
        }

        field_key.reload
        expect(Mobility.with_locale(:en) { field_key.label }).to eq('Apartment')
        expect(Mobility.with_locale(:es) { field_key.label }).to eq('Apartamento')
        expect(Mobility.with_locale(:fr) { field_key.label }).to eq('Appartement')
      end

      it 'updates existing translations' do
        # Set initial translation using Mobility
        Mobility.with_locale(:en) { field_key.label = 'Old Name' }
        field_key.save!

        patch :update, params: {
          category: 'property_types',
          id: field_key.global_key,
          field_key: {
            translations: {
              en: 'New Name'
            }
          }
        }

        field_key.reload
        Mobility.with_locale(:en) do
          expect(field_key.label).to eq('New Name')
        end
      end

      it 'skips blank translations' do
        patch :update, params: {
          category: 'property_types',
          id: field_key.global_key,
          field_key: {
            translations: {
              en: 'Valid',
              es: '',
              fr: nil
            }
          }
        }

        field_key.reload
        expect(Mobility.with_locale(:en) { field_key.label }).to eq('Valid')

        # Blank translations are not saved - only 'en' should be in the translations hash
        # Note: Mobility fallbacks mean es/fr will return the English value when accessed
        expect(field_key.translations.keys).to eq(['en'])
        expect(field_key.translations['es']).to be_nil
        expect(field_key.translations['fr']).to be_nil
      end

      it 'isolates translations per website (tenant)' do
        # Create a field key for other website
        other_field_key = ActsAsTenant.with_tenant(other_website) do
          create(:pwb_field_key, website: other_website, tag: 'property-types')
        end

        # Update field_key for current website
        patch :update, params: {
          category: 'property_types',
          id: field_key.global_key,
          field_key: {
            translations: { en: 'My Apartment' }
          }
        }

        field_key.reload
        expect(Mobility.with_locale(:en) { field_key.label }).to eq('My Apartment')

        # Other website's field key should not be affected
        other_field_key.reload
        expect(Mobility.with_locale(:en) { other_field_key.label }).to be_nil
      end
    end
  end

  describe 'DELETE #destroy' do
    let!(:field_key) do
      ActsAsTenant.with_tenant(website) do
        create(:pwb_field_key, website: website, tag: 'property-types')
      end
    end

    it 'destroys the field key' do
      expect {
        delete :destroy, params: {
          category: 'property_types',
          id: field_key.global_key
        }
      }.to change(Pwb::FieldKey, :count).by(-1)
    end

    it 'redirects to show page with success notice' do
      delete :destroy, params: {
        category: 'property_types',
        id: field_key.global_key
      }

      expect(response).to redirect_to(site_admin_properties_settings_category_path('property_types'))
      expect(flash[:notice]).to eq('Setting deleted successfully')
    end

    it 'does not allow deleting field keys from other websites' do
      other_field_key = ActsAsTenant.with_tenant(other_website) do
        create(:pwb_field_key, website: other_website, tag: 'property-types')
      end

      expect {
        delete :destroy, params: {
          category: 'property_types',
          id: other_field_key.global_key
        }
      }.not_to change(Pwb::FieldKey, :count)
    end
  end

  describe 'category validation' do
    it 'accepts valid categories' do
      %w[property_types property_states property_features property_amenities property_status property_highlights listing_origin].each do |category|
        get :show, params: { category: category }
        expect(response).to have_http_status(:success)
      end
    end

    it 'rejects invalid categories' do
      get :show, params: { category: 'hacked_category' }
      expect(response).to redirect_to(site_admin_root_path)
      expect(flash[:alert]).to eq('Invalid category')
    end
  end

  describe 'authentication' do
    context 'when user is not signed in' do
      before { sign_out :user }

      it 'denies access' do
        get :index
        # May redirect to sign in or return 403 forbidden depending on auth configuration
        expect(response.status).to eq(302).or eq(403)
      end
    end
  end
end
