require 'erubi'
require 'sinatra'
require 'erb'
require 'debci/package'
require 'debci/html_helpers'
require 'debci/user'

module Debci
  class App < Sinatra::Base
    enable :logging
    enable :sessions
    set :session_secret, Debci.config.session_secret || SecureRandom.hex(64)

    set :erb, escape_html: true

    include ERB::Util
    include Debci::HTMLHelpers

    set :erb, escape_html: true
    set :views, "#{File.dirname(__FILE__)}/html/templates"

    before do
      @user = nil
      if session.has_key?(:user_id)
        begin
          @user = Debci::User.find(session[:user_id])
        rescue ActiveRecord::RecordNotFound
          logger.warn("Invalid :user_id in session")
        end
      end
    end

    after do
      session.options[:drop] = !logged_in? && !logging_in?
    end

    def logged_in?
      !@user.nil?
    end

    def logging_in?
      request.path =~ %r{^/user/auth/\w+/callback$} || session.has_key?(:original_url)
    end

    def authenticate!
      return if @user

      session.options[:drop] = false
      session[:original_url] = params[:original_url] || request.path
      redirect('/user/login')
      halt
    end

    def forbidden
      halt 403, erb(:forbidden)
    end

    not_found do
      case request.path
      when %r{^/data/autopkgtest/(\w+)/(\w+)/(\w+)/([^/]+)/(\d+)/log.gz$}
        @suite = ::Regexp.last_match(1)
        @arch = ::Regexp.last_match(2)
        @prefix = ::Regexp.last_match(3)
        @pkgname = ::Regexp.last_match(4)
        @job_id = ::Regexp.last_match(5)
      when %r{^/packages/(\w+)/([^/]+)/(\w+)/(\w+)/(\d+)/$}
        @prefix = ::Regexp.last_match(1)
        @pkgname = ::Regexp.last_match(2)
        @suite = ::Regexp.last_match(3)
        @arch = ::Regexp.last_match(4)
        @job_id = ::Regexp.last_match(5)
      end

      if @pkgname && @job_id
        begin
          @package = Debci::Package.find_by_name(@pkgname)
          @job = @package.jobs.where(suite: @suite, arch: @arch).find(@job_id.to_i)
          # if the job exists, and we get here, by definition the job is
          # expired (because otherwise we would not be in the not found
          # handler).
          erb :log_expired
        rescue ActiveRecord::RecordNotFound
          erb :not_found
        end
      else
        erb :not_found
      end
    end

    def refresh!
      @refresh = true
    end

    def self.get_page_range(current, total)
      full_range = (1..total)
      middle = ((current - 5)..(current + 5)).select { |i| full_range.include?(i) }
      start = middle.include?(1) ? [] : [1, nil]
      finish = middle.include?(total) ? [] : [nil, total]
      start + middle + finish
    end

    def get_page_range(current, total)
      self.class.get_page_range(current, total)
    end

    Page = Struct.new(:current_page, :records, :total_records, :total_pages, :pages)

    def get_page_params(records, page, per_page_limit)
      current_page = page || 1
      total_records = records.count
      records = records.page(current_page).per(per_page_limit)
      total_pages = records.total_pages
      pages = get_page_range(Integer(current_page), total_pages)
      Page.new(current_page, records, total_records, total_pages, pages)
    end

    def pagination_params(page)
      query = {}
      request.env['rack.request.query_hash'].each do |key, value|
        key = "#{key}[]".to_sym if value.is_a?(Array)
        query[key] = value
      end
      query.merge!(page: page)
      URI.encode_www_form(query)
    end
  end
end
