require 'open-uri'

class ArtistController < ApplicationController
  @@default_album_types = ['Album', 'Soundtrack']
  def data
    @data = {
      :status => '',
      :correct_name => '',
      :html => ''
    }
    @loading = false
    
    # Bad params
    if params[:name].nil? or params[:name].length == 0
      @data[:status] = 'loading_failed';
      render :json => @data
      return
    end
    
    # Searching for artist
    name = params[:name].gsub('%20', ' ').gsub('+', ' ').gsub('.html', '')
    @artist = Artist.find_by_name(name)
    
    # Artist not found
    unless @artist
      results = ArtistController.musicBrainzExactSearch(name)
      if results.empty?
        @data[:status] = 'not_found'
        render :json => @data
      elsif results[0][:name] != name and (results[0][:name].downcase == name.downcase or results[0][:name].downcase == 'the '+ name.downcase)
        @data[:status] = 'corrected'
        @data[:correct_name] = results[0][:name]
        render :json => @data
      elsif results[0][:name] == name
        # Saving artist and queueing job
        @artist = Artist.new
        @artist.name = name
        @artist.status = 0
        @artist.save
        Delayed::Job.enqueue LoadArtistJob.new(name)
        # Rendering loading info
        @artist = { :artist => @artist, :albums => [] }
        @loading = true
        @data[:status] = 'loading'
        @data[:html] = (render_to_string :partial => 'page').gsub(/\n\s+/, '').gsub(/\n/, '')
        render :json => @data
      else
        @suggestions = results.take(5)
        @data[:status] = 'suggestions'
        @data[:html] = (render_to_string :partial => 'suggestions').gsub(/\n\s+/, '').gsub(/\n/, '')
        render :json => @data
      end
      return
    end
    
    if @artist and @artist.status == 2
      @data[:status] = 'fail'
      @data[:html] = (render_to_string :partial => 'fail').gsub(/\n\s+/, '').gsub(/\n/, '')
      render :json => @data
      return
    end
    
    if @artist.status == 1
      @data[:status] = 'ok'
    else
      @data[:status] = 'loading'
      @loading = true
    end
    
    @data[:html] = buildArtistHTML(@artist)
    render :json => @data
  end
  
  def buildArtistHTML artist
    @artist[:artist] = {
      id: artist.id,
      name: artist.name,
      desc: ActionController::Base.helpers.strip_tags(artist.desc),
      pic: artist.pic_url
    }
    
    @artist[:albums] = []
    artist.albums.each do |album|
      if @@default_album_types.include? album.album_type and album.status == 1
        tmp_album = {id: album.id, name: album.name, year: album.year, pic: album.pic_url}
        album_tracks = []
        bonus_tracks = []
        album.tracks.each do |track|
          tmp_track = {id: track.id, name: track.name, live: track.live, acoustic: track.acoustic}
          tmp_track[:duration] = formatTrackDuration(track.length)
          (track.bonus == 0 ? album_tracks : bonus_tracks) << tmp_track
        end
        tmp_album[:tracks] = {album: album_tracks, bonus: bonus_tracks}
        @artist[:albums] << tmp_album
      end
    end
    
    (render_to_string :partial => 'page').gsub(/\n\s+/, '').gsub(/\n/, '')
  end
  
  def formatTrackDuration length
    if length
      time = (length / 1000).round
      time_m = (time / 60).floor
      time_s = time - time_m * 60
      time_m.to_s + ':' + (time_s < 10 ? '0' : '') + time_s.to_s
    else
      '0:00'
    end
  end
  
  def autocomplete
  	autocomplete = getLastFmAutocomplete(params[:query])
  	return	render :nothing => true if autocomplete.nil?
  	suggestions = []
    autocomplete["response"]["docs"].each do |doc|
    	suggestions << doc["artist"] unless suggestions.include?(doc["artist"]) or doc["artist"].nil? or doc['restype'] != 6
    end
		render :json => {
			:query => params[:query],
			:suggestions => suggestions.take(5)
		}
	end
	
	def getLastFmAutocomplete query
  	return nil if query.nil? or query.strip.empty?
		json = ActiveSupport::JSON.decode(open(
		  'http://www.last.fm/search/autocomplete' <<
		  '?rows=30&q=' << URI.escape(query)
    ).read)
    json.empty? ? nil : json
	end
	
	def musicBrainzSearch(query)
	  begin
	    response = ActiveSupport::JSON.decode(open('http://search.test.musicbrainz.org/ws/2/artist/?fmt=json&query='+ URI.escape(query).gsub(/\&/, '%26').gsub(/\?/, '%3F') +'~&limit=100').read)
	    artists = []
	    response['artist-list']['artist'].each do |artist|
	      artists << artist['name'] unless artist['type'] == 'unknown'
	    end
	    artists.take(10)
	  rescue
	    {}
	  end
	end
	
	def self.musicBrainzExactSearch(query)
	  begin
	    response = ActiveSupport::JSON.decode(open('http://search.test.musicbrainz.org/ws/2/artist/?fmt=json&query='+
	      URI.escape(query).gsub(/\&/, '%26').gsub(/\?/, '%3F') +'~&limit=50',
	      'User-Agent' => 'BeatHaven.org'
	    ).read)
	    artists = []
	    i = 0
	    response['artist-list']['artist'].each do |artist|
	      i++
	      artist['weight'] = (response['artist-list']['artist'].length - i)
        unless artist['alias-list'].nil?
          artist['weight'] += 20 if artist['alias-list']['alias'].include?(query)
          artist['alias-list']['alias'].each do |aliass|
            artist['weight'] += 10 if aliass.downcase == query.downcase
            artist['weight'] += 3 if aliass.downcase.include?(query.downcase)
          end
        end
	      unless artist['tag-list'].nil?
	        artist['weight'] += artist['tag-list']['tag'].length * 4
	      end
	    end
	    response['artist-list']['artist'].each do |artist|
	      artists << {name: artist['name'], weight: artist['weight'], desc: artist['disambiguation'], type: artist['type'].capitalize, mbid: artist['id']} unless artist['type'] == 'unknown'
	    end
	    artists.sort! { |a, b| b[:weight] <=> a[:weight] }
	    artists.take(10)
	  rescue
	    {}
	  end
	end
end