require_relative 'sprints'

module Trackington
  class ProjectRepository
    def create(user_id, project_information)
      project = Models::Project.new(project_information)
      project.save

      project_role = Models::ProjectRole.new(user_id: user_id,
                                             project_id: project.id,
                                             role_type: :owner)
      project_role.save

      sprint = Models::Sprint.new(project_id: project.id, is_backlog: true)
      sprint.save

      project.id
    end

    def get(project_id)
      db_project = Models::Project.find(project_id)

      Project.new(db_project.id,
                  db_project.title,
                  db_project.description,
                  db_project.public)
    end

    def all(user_id)
      get_projects(user_id: user_id)
    end

    def public
      get_projects(public: true)
    end

    private

    def get_projects(params)
      project_ids = Models::ProjectRole
                    .where(params)
                    .select(:project_id)
                    .map(&:project_id)

      Models::Project.find(project_ids).map do |db_project|
        Project.new(db_project.id, db_project.title, db_project.description,
                    db_project.public)
      end
    end
  end

  class Project
    attr_reader :id, :title, :description, :public, :sprints

    def initialize(id, title, description, public)
      @id = id
      @title = title
      @description = description
      @public = public
      @sprints = SprintRepository.new(@id)
    end

    def add_user(project_user, user_to_add, type = nil)
      check_user_role(project_user, 'owner')

      type ||= 'contributor'

      existing = Models::ProjectRole.where(user_id: user_to_add,
                                           project_id: @id).first

      return unless existing.nil?

      new_role = Models::ProjectRole.new(user_id: user_to_add,
                                         project_id: @id,
                                         role_type: type)

      new_role.save
    end

    def remove_user(project_user, user_to_remove)
      check_user_role(project_user, 'owner')

      Models::ProjectRole.destroy_all(project_id: @id,
                                      user_id: user_to_remove)

      nil
    end

    def update_user(project_user, user, new_type)
      check_user_role(project_user, 'owner')

      role = Models::ProjectRole.where(project_id: @id, user_id: user).first

      role.role_type = new_type

      role.save
    end

    def update(project_user, data)
      check_user_role(project_user, 'owner')

      @title = data[:title]
      @description = data[:description]
      @public = data[:public]

      db_project = Models::Project.find(@id)
      db_project.title = @title
      db_project.description = @description
      db_project.public = @public
      db_project.save
    end

    def current_sprint(project_user)
      check_user_role project_user

      @sprints.current
    end

    def create_sprint(project_user, data)
      check_user_role(project_user, 'owner')

      @sprints.create(data)
    end

    def start_sprint(project_user)
      check_user_role(project_user, 'owner')

      @sprints.start_sprint
    end

    def complete_sprint(project_user)
      check_user_role(project_user, 'owner')

      @sprints.complete_sprint
    end

    def backlog(project_user)
      check_user_role project_user

      @sprints.backlog
    end

    def user_is?(user_id, type)
      role = Models::ProjectRole.where(project_id: @id, user_id: user_id).first

      return false if role.nil?

      return true if role.role_type == 'owner'

      role.role_type == type
    end

    def users
      Models::Project.find(@id).project_roles.map do |role|
        ProjectRole.new(role)
      end
    end

    private

    def check_user_role(user_id, type = 'spectator')
      fail 'User not in role.' unless user_is?(user_id, type)
    end
  end

  class ProjectRole
    attr_reader :user_id, :user_email, :type

    def initialize(project_role)
      @user_id = project_role.user_id
      @user_email = project_role.user.email
      @type = project_role.role_type
    end
  end
end
