module Twitch
  class Team < Service::Base
    include ActiveModel::Validations::Callbacks

    LANDING_PAGE_URL_PREFIX = 'https://www.twitch.tv/team/'.freeze
    MIN_NAME_LENGTH = 3
    MAX_NAME_LENGTH = 25
    MAX_DISPLAY_NAME_LENGTH = 65
    MAX_DESCRIPTION_MARKDOWN_LENGTH = 10_000
    LIMIT = 25

    self.service_endpoint = Settings.roster.endpoint
    self.primary_attribute = :id

    attributes :id,
      :name,
      :display_name,
      :user_id,
      :description_markdown,
      :logo_url,
      :banner_url,
      :background_image_url,
      :created_at,
      :updated_at

    validates :name,
      presence: true,
      length: { in: MIN_NAME_LENGTH..MAX_NAME_LENGTH },
      format: { with: /\A[a-z0-9]([a-z0-9_\-]+[a-z0-9])?\z/ }

    before_validation :downcase_name

    validates :display_name, presence: true, length: { in: 1..MAX_DISPLAY_NAME_LENGTH }
    validates :user_id, presence: true, numericality: { only_integer: true }
    validates_length_of :description_markdown, maximum: MAX_DESCRIPTION_MARKDOWN_LENGTH

    def self.find_by_name(name)
      response = get('/v1/teams', params: { name: name })
      team = response.body['data'].first

      team ? from_attributes(team) : nil
    end

    def self.page(page_number)
      query_params = {
        limit: LIMIT,
        offset: (page_number - 1) * LIMIT,
        sort: 'desc'
      }

      response = get('/v1/teams', params: query_params)
      teams = response.body['data'].map { |team| from_attributes(team) }

      paginate teams, per_page: LIMIT, total_count: response.body['meta']['total']
    end

    def self.search(name:, page: 1)
      query_params = {
        limit: LIMIT,
        name: name,
        offset: (page - 1) * LIMIT
      }

      response = get('/v1/search/teams', params: query_params)
      teams = response.body['data'].map { |team| from_attributes(team) }

      paginate teams, per_page: LIMIT, total_count: response.body['meta']['total']
    end

    def landing_page_url
      "#{LANDING_PAGE_URL_PREFIX}#{@name}"
    end

    def dashboard_url
      "https://www.twitch.tv/teams/#{@name}/dashboard"
    end

    def destroy
      response = delete("/v1/teams/#{@id}")

      unless response.success?
        case response.status
        when 404
          raise 'Team not found'
        else
          raise "Unexpected response (#{response.status}) when deleting team"
        end
      end

      true
    end

    def persisted?
      @id.present?
    end

    def save
      return false unless valid?
      return true if persisted?

      body = {
        name: @name,
        display_name: @display_name,
        description_markdown: @description_markdown
      }

      response = post("/v1/users/#{@user_id}/teams", body: body.to_json)

      unless response.success?
        message = response.body['message']

        case response.status
        when 404
          errors.add(:user_id, :invalid, message: message)
        else
          errors.add(:base, :invalid, message: message)
        end

        return false
      end

      true
    end

    # Teams are identified by `name` and not `id` in the URL.
    # We want to rely on `form_for` to build the form action and HTTP verb.
    def to_param
      name
    end

    def update(attributes)
      @display_name = attributes[:display_name]
      @user_id = attributes[:user_id]
      @description_markdown = attributes[:description_markdown]

      return false unless valid?

      body = {
        display_name: @display_name,
        user_id: @user_id,
        description_markdown: @description_markdown
      }

      response = patch("/v1/teams/#{@id}", body: body.to_json)

      unless response.success?
        message = response.body['message']

        case response.status
        when 404
          raise 'Team not found'
        when 422
          errors.add(:user_id, :invalid, message: message)
        else
          errors.add(:base, :invalid, message: message)
        end

        return false
      end

      true
    end

    private

    def downcase_name
      @name.downcase!
    end
  end
end
