# TODO: Remove this disable
# rubocop:disable Metrics/ClassLength
require_dependency "renalware/letters"

module Renalware
  module Letters
    class LettersController < Letters::BaseController
      before_action :load_patient, except: [:author]

      def index
        render :index, locals: { letters: present_letters(find_letters) }
      end

      def author
        user = Renalware::User.find(params[:author_id])
        author = Letters.cast_author(user)
        letters = author.letters
        authorize letters
        render locals: {
          author: author,
          letters: present_letters(letters)
        }
      end

      def new
        @patient = load_and_authorize_patient
        letter = LetterFactory
          .new(@patient,
               event: find_event,
               author: current_user,
               clinical: clinical?)
          .with_contacts_as_default_ccs
          .build
        RememberedLetterPreferences.new(session).apply_to(letter)
        render_form(letter, :new)
      end

      def create
        attributes = letter_params.merge(event: find_event)
        DraftLetter.build
          .subscribe(self)
          .call(@patient, attributes)
      end

      def destroy
        load_and_authorize_patient
        letter = find_letter(params[:id])
        authorize letter
        letter.destroy
        redirect_to patient_letters_letters_path(patient)
      end

      def draft_letter_successful(letter)
        RememberedLetterPreferences.new(session).persist(letter)
        redirect_to_letter_show(@patient, letter)
      end

      def draft_letter_failed(letter)
        flash.now[:error] = t(".failed", model_name: "Letter")
        render_form(letter, :new)
      end

      def show
        @letter = present_letter(find_letter(params[:id]))
      end

      def edit
        render_form(find_letter(params[:id]), :edit)
      end

      def update
        ReviseLetter.build
          .subscribe(self)
          .call(@patient, params[:id], letter_params)
      end

      def revise_letter_successful(letter)
        redirect_to_letter_show(@patient, letter)
      end

      def revise_letter_failed(letter)
        flash.now[:error] = t(".failed", model_name: "Letter")
        render_form(letter, :edit)
      end

      def contact_added
        contact = @patient.contacts.find(params[:id])
        @contact = ContactPresenter.new(contact)
        @letter = LetterFormPresenter.new(Letter.new)
      end

      private

      def load_and_authorize_patient
        patient = Patient.includes(:prescriptions).find_by(secure_id: params[:patient_id])
        authorize patient
        patient
      end

      def find_letters
        @patient.letters
          .with_main_recipient
          .with_letterhead
          .with_author
          .with_event
          .with_patient
      end

      def find_letter(id)
        @patient.letters.find(id)
      end

      def present_letters(letters)
        CollectionPresenter.new(letters, LetterPresenterFactory)
      end

      def present_letter(letter)
        LetterPresenterFactory.new(letter)
      end

      def redirect_to_letter_show(patient, letter)
        redirect_to patient_letters_letter_path(patient, letter)
      end

      def clinical?
        params[:clinical].present?
      end

      def render_form(letter, action)
        letter = LetterFormPresenter.new(letter)
        contacts = find_contacts
        contact = build_contact
        render action, locals: {
          patient: @patient, letter: letter, contact: contact,
            contacts: contacts, contact_descriptions: find_contact_descriptions
        }
      end

      def find_event
        return if event_type.blank?
        event_class.for_patient(@patient).find(event_id)
      end

      def find_contact_descriptions
        CollectionPresenter.new(ContactDescription.ordered, ContactDescriptionPresenter)
      end

      def find_contacts
        ContactsPresenter.new(@patient.contacts.with_description.ordered, ContactPresenter)
      end

      def build_contact
        Contact.new.tap(&:build_person)
      end

      def event_class
        @event_class ||= event_type.singularize.classify.constantize
      end

      def event_type
        params.fetch(:event_type, nil)
      end

      def event_id
        params.fetch(:event_id, nil)
      end

      def letter_params
        params
          .require(:letter)
          .permit(attributes)
          .merge(by: current_user)
      end

      def attributes
        [
          :event_type, :event_id, :clinical,
          :letterhead_id, :author_id, :description, :issued_on, :enclosures,
          :salutation, :body, :notes,
          main_recipient_attributes: main_recipient_attributes,
          cc_recipients_attributes: cc_recipients_attributes
        ]
      end

      def main_recipient_attributes
        [
          :id, :person_role, :addressee_id
        ]
      end

      def cc_recipients_attributes
        [
          :id, :person_role, :addressee_id, :_keep
        ]
      end

      def address_attributes
        [
          :id, :name, :organisation_name, :street_1, :street_2, :street_3, :town, :county,
          :postcode, :country, :telephone, :email, :_destroy
        ]
      end
    end
  end
end