require 'routing_constraints'

System::Application.routes.draw do

  resource :openid

  if ThreeScale::Core.url == System::Application.config.three_scale.core.fake_server
    internal = proc do |env|
      [
        200,
        { 'Content-Type' => 'application/json', 'Content-Length' => 2},
        ['{}']
      ]
    end

    constraints DomainConstraint.new(URI(ThreeScale::Core.url).host) do
      mount internal, at: 'internal'
    end
  elsif System::Application.config.three_scale.core.fake_server
    warn <<-WARNING
[config/routes.rb] You need more than 1 unicorn worker to run fake Core server
without fake Core server your after commit callbacks will crash and you might get unexpected failures
    WARNING
  end

  constraints BuyerDomainConstraint do
    # Just for a better user experience,
    # unless should show the message:
    #     "is not accessible on domain vodafone.3scale.net"
    get '/p/admin/dashboard', to: redirect('/admin')
  end

  #
  #   Master
  #

  constraints MasterOrProviderDomainConstraints do
    namespace :master, module: 'master' do
      namespace :events, :module => 'events', :defaults => { :format => 'xml' } do
        resource :import, :only => :create
      end
    end
  end

  constraints MasterDomainConstraint do
    constraints LoggedInConstraint do
      mount ::Resque::Server, at: 'resque'
      mount ::Sidekiq::Web, at: 'sidekiq'
      mount ::System::Deploy, at: 'deploy'
    end

    get "status" => "application#status"
    namespace :partners do
      resources :providers, defaults: {format: 'json'} do
        resources :users, only: [:create, :destroy, :index, :show]
      end
      resource :sessions do
        member do
          get "openid"
        end
      end
    end

    namespace :heroku do
      resources :resources, only: [:create, :update, :destroy]
      resource :sessions, only: [:create], path: 'sso'
    end

    namespace :master, module: 'master' do

      namespace :devportal do
        get '/auth/:system_name/callback/' => 'auth#show'
        get '/auth/invitations/:invitation_token/:system_name/callback' => 'auth#show'
        get '/auth/invitations/auth0/:system_name/callback' => 'auth#show'
      end

      namespace :api, defaults: {format: 'json'} do
        resources :providers do
          member do
            post :change_partner
          end
          resources :services, only: [:destroy]
        end
      end

      resources :providers, module: 'providers', only: [] do
        resource :plan, only: [ :update, :edit ]
        resources :switches, only: [ :update, :destroy ]
      end
    end
  end

  resource :raise, :only => [:show]

  get '/stylesheets/theme.css' => 'cms/stylesheets#show', :as => :cms_stylesheet, :name => 'theme'
  get '/stylesheets/provider_customized.css' => 'cms/stylesheets#show', :as => :cms_stylesheet_provider, :name => 'provider_customized'

  post '/experiments/report' => 'google_experiments#report'

  namespace :provider, :path => 'p', constraints: MasterOrProviderDomainConstraints do

    get 'activate/:activation_code' => 'activations#create', :as => :activate

    resource :password, :only => [:show, :update, :destroy]
    resource :domains, :only => [:show] do
      collection do
        post :recover
      end
    end


    resource :signup, :only => [:show, :create] do
      match '', action: :cors, via: 'OPTIONS'
      match '*path', action: :cors, via: 'OPTIONS'

      collection do
        get :success
        get :test, as: :iframe
        get :testab
        get :ab
        get :clean
      end
    end

    # BEWARE: those 2 routes have to be below /p/signup/success or
    # they would override it.
    resource :invitee_signup, path: "signup/:invitation_token", only: [:show, :create]

    resource :sessions, :only => [:new, :create, :destroy, :show]
    get 'sso' => 'sessions#create'
    get 'login'  => 'sessions#new',     :as => :login
    get 'logout' => 'sessions#destroy', :as => :logout

    get 'admin', to: 'admin#show'

    namespace :admin do
      resource :sudo, only: [:new, :show, :create]

      resources :authentication_providers
      resource :dashboard, :only => [:show]

      namespace :dashboard do
        resource :new_accounts, only: [:show]
        resource :potential_upgrades, only: [:show]

        namespace :service, path: 'service/:service_id', as: :service do
          resource :hits, only: [:show]
          resource :integration_errors, only: [:show]
          resource :top_traffic, only: [:show], controller: :top_traffic
        end
      end

      resource :go_live_state, only: [:show, :update]
      resource :account, :only => [:show, :edit, :update]
      resource :api_docs, :only => [:show]
      resource :liquid_docs, :only => [:show]
      resource :webhooks, :only => [ :new, :edit, :create, :update, :show ]
      resources :destroys, :only => [:index]

      namespace :onboarding do
        namespace :wizard do
          root to: 'info#index'

          get 'intro' => 'info#intro'
          get 'explain' => 'info#explain'
          resource :api, only: [:new, :edit, :update], controller: :api
          resource :request, only: [:new, :edit, :update, :show], controller: :request
          get 'outro' => 'info#outro'
        end
      end

      namespace :messages do
        root to: 'inbox#index'
        resources :inbox, only: [:show, :destroy] do
          member do
            post :reply
          end
        end
        resources :outbox, except: [:edit, :update]
        resources :trash, only: [:index, :show, :destroy] do
          collection do
            delete :empty # delete all
          end
        end

        namespace :bulk do
          resource :trash, only: [:new, :create]
        end
      end

      namespace :api_docs do
        resource :account_data, :only => [:show]
        resources :specs, only: :show
      end

      scope 'applications/:application_id', :as => :application do
        resources :keys, :only => [ :new, :create, :edit, :update, :destroy ] do
          member do
            put :regenerate
          end
        end
        resources :referrer_filters, :only => [:create, :destroy]
      end

      namespace :cms do
        root to: 'templates#index'
        resources :templates, only: [:index] do
          collection do
            get :sidebar
          end

          resources :versions, only: [:index, :show, :destroy] do

            member do
              post :revert
            end
          end
        end

        resources :builtin_sections, controller: 'sections', except: [ :show, :destroy ]

        resources :sections, :except => [:show] do
          resources :changes
        end

        resources :builtin_static_pages, :builtin_pages, :builtin_partials, only: [:edit, :update] do
          member do
            put :publish
          end
        end

        resources :pages, :layouts, :partials, except: [:show, :index] do
          member do
            put :publish
          end
        end

        resources :email_templates, :except => [:show]
        resources :builtin_legal_terms, :except => [ :show, :index ]

        resources :portlets, :except => [:show] do
          collection do
            get :pick
          end
          member do
            put :publish
          end

        end

        resources :switches, :only => [ :index, :update, :destroy ]
        resources :files, :except => [:show]
        resources :redirects, :except => [:show]
        resources :sections, :except => [:show]
        resources :groups, :except => [:show]
        resources :changes do
          collection do
            put :publish_all
          end
          member do
            put :publish
            put :revert
          end

        end
      end

      namespace :user do
        resource :notification_preferences, only: [:show, :update]
        resource :personal_details, only: [:edit, :update]
        resources :access_tokens, only: [:index, :new, :create, :edit, :update, :destroy]
      end

      namespace :account do
        resources :notifications, :only => [:index, :update]
        resources :users, :only => [:index, :edit, :update, :destroy] do
          resources :access_tokens, only: [:index, :new, :create, :edit, :update, :destroy]
        end

        resource :braintree_blue, only: [:show, :edit, :update, :destroy], module: 'payment_gateways' do
          match 'hosted_success', via: [:get, :post], on: :member
        end
        resource :data_exports, :only => [:new, :create]
        resource :logo, :only => [:edit, :update, :destroy]

        resources :invitations, :only => [:index, :new, :create, :destroy] do
          member do
            put :resend
          end
        end

        resource :personal_details, only: [] do
          match '/', via: :any, to: redirect { Rails.application.routes.url_helpers.edit_provider_admin_user_personal_details_path }
          get 'edit', action: 'edit', on: :member, to: redirect { Rails.application.routes.url_helpers.edit_provider_admin_user_personal_details_path }
        end

        resource :change_plan, :only => [:show, :update] do
          member do
            get :widget
          end
        end

        resources :invoices, :only => [:show, :index]
      end
    end
  end

  namespace :api_docs do
    get 'track.:format' => 'tracking#update', :as => :check
  end

  # only for the admin/buyers stuff that dont have admin in route name
  namespace :buyers, :as => 'admin', :path => 'admin/buyers' do
    resources :account_plans, :only => [:new, :create, :edit, :update, :destroy] do
      collection do
        post :masterize
      end
      member do
        post :copy
      end
    end
  end

  get '/admin/apiconfig/services/:service_id/applications' => 'buyers/applications#index', :as => 'admin_service_applications'

  # These are API routes, beware
  namespace :stats do
    namespace :data, :path => '' do
      # horrible hacks with path to get parameter to be named :service_id
      resources :services, :path => 'services/:service_id' do  #, :applications do
        collection do
          get 'usage'
          get 'usage_response_code'
          get 'top_applications'
          get 'summary'
        end
      end
      resources :applications, :path => 'applications/:application_id' do
        collection do
          get 'usage'
          get 'usage_response_code'
          get 'summary'
        end
      end
    end
  end

  get '/check.txt' => 'checks#check'
  get '/check/error' => 'checks#error'
  get '/search/forum' => 'search#forum'

  namespace :admin do # this is different from the scope that follows as the controllers are in the admin module

    namespace :account do
      resource :payment_gateway, :only => [:update]
    end

    namespace :api_docs do
      resources :services do
        member do
          get :preview
          put :toggle_visible
        end
      end
    end

    resources :web_hooks, :only => [:index, :create, :update] do
      member do
        post :ping
      end
    end
    resource :user_confirmation, :only => :create
    resources :fields_definitions do
      collection do
        post :sort
      end
    end

    resources :upgrade_notices, :only => [:show]

    # api routes, be careful
    namespace :api, :defaults => { :format => 'xml' } do

      # called from heroku deploy hook after heroku proxy deploy script
      post 'heroku-proxy/deployed', to: 'heroku_proxy#deployed', as: :heroku_proxy_deployed

      # /admin/api/provider
      resource :provider, only: [:show, :update]

      namespace(:cms) do
        resources :sections do
          resources :files, only: :index
          #resources :templates, only: :index
          #resources :sections, only: :index
        end
        resources :files
        resources :templates, :only => [ :index, :create, :show, :update, :destroy ] do
          member do
            put :publish
          end
        end
      end

      resources :sso_tokens, :only => :create
      resources :accounts, :only => [:index, :show, :update, :destroy] do
        collection do
          get :find
        end

        member do
          put :change_plan
          put :make_pending
          put :approve
          put :reject
        end

        resource :credit_card, :only => [:update, :destroy]
        resources :users, :controller => 'buyers_users', :except => [:new, :edit] do
          member do
            put :admin
            put :member
            put :suspend
            put :activate
            put :unsuspend
          end
        end

        resources :application_plans, :controller => 'buyers_application_plans', :only => :index do
          member do
            post :buy
          end
        end
        resource :plan, :as => 'buyer_account_plan',:controller => 'buyer_account_plans', :only => :show
        resources :service_plans, :controller => 'buyers_service_plans', :only => :index do
          member do
            post :buy
          end
        end

        resources :applications, :controller => 'buyers_applications', :only => [:index, :show, :create, :update, :destroy] do
          collection do
            get :find
          end
          member do
            put :change_plan
            put :customize_plan
            put :decustomize_plan
            put :accept
            put :suspend
            put :resume
          end
          resources :keys, :controller => 'buyer_application_keys', :only => [:index, :create, :destroy]
          resources :referrer_filters, :controller => 'buyer_application_referrer_filters', :only => [:index, :create, :destroy]
        end

        resources :messages, :only => [:create]
      end

      resources :account_plans, :except => [:new, :edit] do
        member do
          put :default
        end
        resources :features, :controller => 'account_plan_features', :only => [:index, :create, :destroy]
      end

      resources :active_docs, :controller => 'api_docs_services', :only => [:index, :update, :create, :destroy]

      resources :application_plans, :only => [:index] do
        resources :pricing_rules, :controller => 'application_plan_pricing_rules', :only => [:index ]
        resources :features, :controller => 'application_plan_features', :only => [:index, :create, :destroy]
        resources :limits, :controller => 'application_plan_limits', :only => :index

        resources :metrics, :only => [] do
          resources :limits, :controller => 'application_plan_metric_limits', :except => [:new, :edit]
          resources :pricing_rules, :controller => 'application_plan_metric_pricing_rules', only: [:index, :create]
        end
      end

      resources :applications, :only => [:index] do
        collection do
          get :find
        end
      end

      resource :signup, :only => :create
      resources :users, :except => [:new, :edit] do
        member do
          put :admin
          put :member
          put :suspend
          put :activate
          put :unsuspend
        end
      end
      resources :end_user_plans, :only => [:index] do
        scope module: :end_user_plans do
          resources :metrics, :only => [] do
            resources :limits, :except => [:new, :edit]
          end
        end
      end

      resources :service_plans, :only => [:index] do
        resources :features, :controller => 'service_plan_features', :only => [:index, :create, :destroy]
      end

      resources :features, :controller => 'account_features', :except => [:new, :edit]

      resource :nginx, :only => [:show], :defaults => { :format => 'zip' } do
        collection do
          get :spec
        end
      end

      resources :services, :except => [:new, :edit] do
        resources :metrics, :except => [:new, :edit] do
          resources :methods, :controller => 'metric_methods', :except => [:new, :edit]
        end

        resources :features, :controller => 'service_features', :except => [:new, :edit]

        resources :service_plans, :except => [:new, :edit] do
          member do
            put :default
          end
        end

        resources :application_plans, :except => [:new, :edit] do
          member do
            put :default
          end
        end

        scope module: :services do # this api has a knack for inconsistency
          resources :end_users, :only => [:show, :create, :destroy] do
            member do
              put :change_plan
            end
          end

          resources :end_user_plans, :except => [:new, :edit, :destroy] do
            member do
              put :default
            end
          end

          resource :proxy, only: %i[show update] do
            resources :mapping_rules, only: %i[index show update destroy create]
          end

          namespace :proxy do
            resources :configs, param: :version, path: 'configs/:environment', only: [:index, :show] do
              get :latest, on: :collection
              post :promote, on: :member
            end
          end

          collection do
            namespace :proxy do
              resources :configs, param: :version, path: 'configs/:environment', only: [] do
                get :index, on: :collection, action: :index_by_host
              end
            end
          end
        end

      end
      resource :webhooks, controller: 'web_hooks', only: [:update] do
        resource :failures, controller: 'web_hooks_failures', only: [:show, :destroy]
      end
      resource :settings, only: [:show, :update]
    end
  end

  # TODO: move this route to DeveloperPortal when this
  # functionality is completely removed from the provider
  # side (it is currently only guarding edge environment
  match 'access_code' => 'developer_portal/access_codes#show', :as => :access_code, :via => [:post, :get]

  constraints ProviderDomainConstraint do

    namespace :api_docs do
      resources :services, only: [:index, :show]
    end

    root :to => redirect('/p/admin')
    get '/admin', to: redirect('/p/admin')

    match '/api_docs/proxy' => 'api_docs/proxy#show', via: [:get, :post]

    scope :path => 'admin', :as => 'admin' do
      namespace :stats do
        root :to => 'dashboards#index'
      end
    end

    admin_module = -> do
      scope :path => 'apiconfig', :module => 'api' do
        get '/' => 'services#index', :as => :apiconfig_root, :namespace => 'api/', :path_prefix => 'admin/apiconfig'
        resources :plans, :only => [] do
          member do
            post :publish
            post :hide
          end
          resources :features, :except => [:index]
          resources :featurings, :only => [:create, :destroy]
        end

        resources :plan_copies, :only => [:new, :create]
        resources :service_plans, :only => [:show, :edit, :update, :destroy]
        resources :application_plans, :only => [:show, :edit, :update, :destroy]
        resources :end_user_plans, :only => [:show, :edit, :update, :destroy]

        resources :application_plans, :end_user_plans, only: [] do
          resources :metrics, only: [] do
            member do
              put :toggle_visible
              put :toggle_enabled
              put :toggle_limits_only_text
            end

            resources :pricing_rules, :only => [:index, :new, :create]
            resources :usage_limits, :only => [:index, :new, :create]
          end

          resources :usage_limits, :only => [:edit, :update, :destroy]
        end

        resources :application_plans, only: [] do
          resources :pricing_rules, :only => [:edit, :update, :destroy]
        end

        resources :services do
          member do
            get :settings
            get :notifications
          end
          resource :support, :only => [:edit, :update]
          resource :content, :only => [:edit, :update]
          resource :terms, :only => [:edit, :update]
          resources :metrics, :except => [:show] do
            resources :children, :controller => 'metrics', :only => [:new, :create]
          end

          resources :application_plans, :only => [:index, :new, :create] do
            collection do
              post :masterize
            end
            member do
              post :copy
            end
          end

          resources :service_plans, :only => [:index, :new, :create] do
            collection do
              post :masterize
            end
            member do
              post :copy
            end
          end

          resources :end_user_plans, :only => [:index, :new, :create] do
            collection do
              post :masterize
            end
          end

          # id constraint to allow uuid style routes
          resources :end_users, :constraints => { :id => /[^\/]+/ }
          resources :alerts, :only => [:index, :destroy] do
            collection do
              put :all_read
              delete :purge
            end
            member do
              put :read
            end
          end

          resource :integration, :except => [ :create, :destroy ] do
            member do
              patch 'update_production'
              patch 'update_onpremises_production'
              patch 'promote_to_production'
            end
          end
          resources :proxy_logs, :only => [:index, :show ]
          resources :proxy_configs, only: %i(index show)
        end

        resources :transactions, :only => :index
        resources :errors, :only => :index do
          collection do
            delete :purge, :path => ''
          end
        end

        resources :alerts, :only => [:index, :destroy] do
          collection do
            put :all_read
            delete :purge
          end
          member do
            put :read
          end
        end
      end # end scope :api

      resources :services, :only => [] do
        resource :graphs, only: [:show]
        namespace :stats do
          root :to => 'dashboards#show'
          get '/signups' => 'dashboards#signups', :as => :signups
          get 'usage' => 'usage#index', :as => :usage
          get 'usage/data/:metric_id' => 'usage#index_data', :as => :usage_data
          get 'usage/top_applications' => 'usage#top_applications', :as => :top_applications
          get 'usage/hours' => 'usage#hours', :as => :hours
          resources :days, :only => :index
          get 'days/:id/:metric_id' => 'days#show', :as => :day
          resource :response_codes, only: [:show]
        end

        resources :log_requests, :only => [:index], :module => 'admin'
        delete 'purge_logs' => 'admin/log_requests#purge', :as => :purge_logs
        namespace :monitor do
          resources :uptimes,        :only => :index
          resources :response_times, :only => :index
          resources :events,         :only => :index
        end
      end # end resources :services

      # to kind of live under buyers namespace, but do not share the Buyers module
      namespace :stats, as: :buyers_stats, path: 'buyers/stats' do
        resources :applications, :only => :show
      end

      namespace :buyers do
        resources :accounts do
          member do
            post :approve
            post :reject
            post :suspend
            post :resume
            put :toggle_monthly_billing
            put :toggle_monthly_charging
          end

          resource :impersonation, :only => [:create]

          resources :users, :except => [:new, :create] do
            member do
              post :suspend
              post :unsuspend
              post :activate
            end
          end

          resources :configs, :only => [:index, :update, :destroy]
          resources :invitations, :only => [:index, :new, :create, :destroy] do
            member do
              put :resend
            end
          end

          resources :applications do
            resources :log_requests, :only => [:index]
            delete 'purge_logs' => 'log_requests#purge', :as => :purge_logs
          end

          resources :service_contracts, :except => [:index, :delete, :show] do
            collection do
              get :services
            end
            member do
              put :change_plan
            end
          end

          resources :invoices, :only => [:index, :show, :create, :edit, :update]
          resource :groups, :only => [:show, :update]
        end

        namespace :accounts do
          namespace :bulk do
            resource :send_email, :only => [:new, :create]
            resource :change_plan, :only => [:new, :create]
            resource :change_state, :only => [:new, :create]
            resource :delete, :only => [:new, :create]
          end
        end
        resources :account_contracts, :only => :update
        resources :account_plans, :only => [:index, :new, :create] do
          collection do
            post :masterize
          end
        end
        resources :service_contracts, :only => [:index]
        resources :contracts, :only => [] do
          resources :custom_plans, :only => [:create, :destroy]
          resources :custom_application_plans, :only => [:create, :destroy]
        end
        resources :applications do

          member do
            put :accept
            delete :reject
            post :suspend
            post :resume
            put :change_user_key
            put :change_plan
            get :edit_redirect_url
          end

        end
        namespace :applications do
          namespace :bulk do
            resource :send_email, :only => [:new, :create]
            resource :change_plan, :only => [:new, :create]
            resource :change_state, :only => [:new, :create]
          end
        end
        namespace :service_contracts do
          namespace :bulk do
            resource :send_email, :only => [:new, :create]
            resource :change_plan, :only => [:new, :create]
            resource :change_state, :only => [:new, :create]
          end
        end
      end # end namespace :buyers

      namespace :finance do
        root :to => 'provider/dashboards#show'

        scope :module => 'provider' do
          resources :invoices, :only => [:index, :show, :update, :create, :edit] do
            member do
              put :pay
              put :generate_pdf
              put :cancel
              put :charge
              put :issue
            end
            resources :line_items, :only => [:new, :create, :destroy]
          end

          resources :accounts, :only => [] do
            resources :invoices, :only => [:index, :show, :update, :create] do
              # member do
              #   put :pay
              #   put :generate_pdf
              #   put :cancel
              #   put :charge
              #   put :issue
              # end
              resources :line_items, :only => [:new, :create, :destroy]
            end
          end

          resource :settings
          resources :log_entries, :only => :index
          resource :billing_strategy, :only => :update
        end
      end # end namespace :finance

      scope :module => 'forums' do
        scope :module => 'admin' do
          resource :forum do
            resources :categories
            resources :posts, :only => [:index, :edit, :update, :destroy]
            resources :topics, :except => :index do
              collection do
                get :my
              end

              resources :posts, :only => :create
            end

            resources :subscriptions, :controller => 'user_topics', :only => [:index, :create, :destroy]
          end
        end
      end # end scope :forums

      namespace :site, :module => 'sites' do # the controller is in the sites module, not site *sigh*

        resource :usage_rules, only: [:edit, :update]
        resource :settings, only: [:show, :edit, :update] do
          member do
            get :policies
          end
        end

        resource :applications, only: [:edit, :update]
        resource :documentation, only: [:edit, :update]


        resource :developer_portal, only: [:edit, :update]

        resource :dns, only: [:show, :update] do
          member do
            put :open_portal
            get :contact_3scale
          end
        end
        resource :forum, only: [:edit, :update]
        resource :spam_protection, only: [:edit, :update]
        resource :emails, only: [ :edit, :update ]
      end
    end
    scope as: :admin, &admin_module

    # Finance API
    scope :module => 'finance' do
      namespace :api do
        resources :invoices, :only => [:index, :show] do
          resources :payment_transactions, only: :index
          resources :line_items, only: :index
          member do
            put :state
          end
        end

        resources :accounts, :only => [], module: 'accounts' do
          resources :invoices, :only => [:index, :show]
        end

      end
    end
  end

  constraints BuyerDomainConstraint do

    scope :module => 'forums' do
      scope :module => 'public' do
        resource :forum, :only => "show" do
          resources :categories, only: [:index, :show]
          resources :posts, :only => [:index, :edit, :update, :destroy]
          resources :topics, :except => :index do
            collection do
              get :my
            end
            resources :posts, :only => [:create]
          end
          resources :subscriptions, :controller => 'user_topics', :only => [:index, :create, :destroy]
        end
      end
    end

    mount DeveloperPortal::Engine, at: "/", as: :developer_portal
  end

  if Rails.env.development? || Rails.env.test?
    mount MailPreview => 'mail_preview'
  end
end
