# frozen_string_literal: true

module Api
  module V1
    class GridArtifactsController < Api::V1::ApiController
      before_action :find_grid_artifact, only: %i[update destroy sync]
      before_action :find_party, only: %i[create update destroy sync]
      before_action :find_grid_character, only: %i[create]
      before_action :find_artifact, only: %i[create]
      before_action :authorize_party_edit!, only: %i[create update destroy sync]

      # POST /grid_artifacts
      def create
        # Check if grid_character already has an artifact
        if @grid_character.grid_artifact.present?
          @grid_character.grid_artifact.destroy
        end

        @grid_artifact = GridArtifact.new(
          grid_artifact_params.merge(
            grid_character_id: @grid_character.id,
            artifact_id: @artifact.id
          )
        )

        if @grid_artifact.save
          render json: GridArtifactBlueprint.render(@grid_artifact, view: :nested, root: :grid_artifact), status: :created
        else
          render_validation_error_response(@grid_artifact)
        end
      end

      # PATCH/PUT /grid_artifacts/:id
      def update
        if @grid_artifact.update(grid_artifact_params)
          render json: GridArtifactBlueprint.render(@grid_artifact, view: :nested, root: :grid_artifact), status: :ok
        else
          render_validation_error_response(@grid_artifact)
        end
      end

      # DELETE /grid_artifacts/:id
      def destroy
        if @grid_artifact.destroy
          render json: GridArtifactBlueprint.render(@grid_artifact, view: :destroyed), status: :ok
        else
          render_unprocessable_entity_response(
            Api::V1::GranblueError.new(@grid_artifact.errors.full_messages.join(', '))
          )
        end
      end

      # POST /grid_artifacts/:id/sync
      def sync
        unless @grid_artifact.collection_artifact.present?
          return render_unprocessable_entity_response(
            Api::V1::GranblueError.new('No collection artifact linked')
          )
        end

        @grid_artifact.sync_from_collection!
        render json: GridArtifactBlueprint.render(@grid_artifact.reload,
                                                  root: :grid_artifact,
                                                  view: :nested)
      end

      private

      def find_grid_artifact
        @grid_artifact = GridArtifact.find_by(id: params[:id])
        render_not_found_response('grid_artifact') unless @grid_artifact
      end

      def find_party
        @party = if @grid_artifact
                   @grid_artifact.grid_character.party
                 else
                   Party.find_by(id: params[:party_id])
                 end
        render_not_found_response('party') unless @party
      end

      def find_grid_character
        @grid_character = GridCharacter.find_by(id: params.dig(:grid_artifact, :grid_character_id))
        render_not_found_response('grid_character') unless @grid_character
      end

      def find_artifact
        artifact_id = params.dig(:grid_artifact, :artifact_id)
        @artifact = Artifact.find_by(id: artifact_id)
        render_not_found_response('artifact') unless @artifact
      end

      def authorize_party_edit!
        if @party.user.present?
          authorize_user_party
        else
          authorize_anonymous_party
        end
      end

      def authorize_user_party
        return if current_user.present? && @party.user == current_user

        render_unauthorized_response
      end

      def authorize_anonymous_party
        provided_edit_key = edit_key.to_s.strip.force_encoding('UTF-8')
        party_edit_key = @party.edit_key.to_s.strip.force_encoding('UTF-8')
        return if valid_edit_key?(provided_edit_key, party_edit_key)

        render_unauthorized_response
      end

      def valid_edit_key?(provided_edit_key, party_edit_key)
        provided_edit_key.present? &&
          provided_edit_key.bytesize == party_edit_key.bytesize &&
          ActiveSupport::SecurityUtils.secure_compare(provided_edit_key, party_edit_key)
      end

      def grid_artifact_params
        params.require(:grid_artifact).permit(
          :grid_character_id, :artifact_id, :collection_artifact_id,
          :element, :proficiency, :level, :reroll_slot,
          skill1: %i[modifier strength level],
          skill2: %i[modifier strength level],
          skill3: %i[modifier strength level],
          skill4: %i[modifier strength level]
        )
      end
    end
  end
end
