// Copyright 2021 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package linode

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
)

// SDMock is the interface for the Linode mock.
type SDMock struct {
	t      *testing.T
	Server *httptest.Server
	Mux    *http.ServeMux
}

// NewSDMock returns a new SDMock.
func NewSDMock(t *testing.T) *SDMock {
	return &SDMock{
		t: t,
	}
}

// Endpoint returns the URI to the mock server.
func (m *SDMock) Endpoint() string {
	return m.Server.URL + "/"
}

// Setup creates the mock server.
func (m *SDMock) Setup() {
	m.Mux = http.NewServeMux()
	m.Server = httptest.NewServer(m.Mux)
}

// ShutdownServer creates the mock server.
func (m *SDMock) ShutdownServer() {
	m.Server.Close()
}

const tokenID = "7b2c56dd51edd90952c1b94c472b94b176f20c5c777e376849edd8ad1c6c03bb"

// HandleLinodeInstancesList mocks linode instances list.
func (m *SDMock) HandleLinodeInstancesList() {
	m.Mux.HandleFunc("/v4/linode/instances", func(w http.ResponseWriter, r *http.Request) {
		if r.Header.Get("Authorization") != fmt.Sprintf("Bearer %s", tokenID) {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}

		w.Header().Set("content-type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusOK)

		fmt.Fprint(w, `
{
  "data": [
    {
      "id": 26838044,
      "label": "prometheus-linode-sd-exporter-1",
      "group": "",
      "status": "running",
      "created": "2021-05-12T04:23:44",
      "updated": "2021-05-12T04:23:44",
      "type": "g6-standard-2",
      "ipv4": [
        "45.33.82.151",
        "96.126.108.16",
        "192.168.170.51",
        "192.168.201.25"
      ],
      "ipv6": "2600:3c03::f03c:92ff:fe1a:1382/128",
      "image": "linode/arch",
      "region": "us-east",
      "specs": {
        "disk": 81920,
        "memory": 4096,
        "vcpus": 2,
        "gpus": 0,
        "transfer": 4000
      },
      "alerts": {
        "cpu": 180,
        "network_in": 10,
        "network_out": 10,
        "transfer_quota": 80,
        "io": 10000
      },
      "backups": {
        "enabled": false,
        "schedule": {
          "day": null,
          "window": null
        },
        "last_successful": null
      },
      "hypervisor": "kvm",
      "watchdog_enabled": true,
      "tags": [
        "monitoring"
      ]
    },
    {
      "id": 26848419,
      "label": "prometheus-linode-sd-exporter-2",
      "group": "",
      "status": "running",
      "created": "2021-05-12T12:41:49",
      "updated": "2021-05-12T12:41:49",
      "type": "g6-standard-2",
      "ipv4": [
        "139.162.196.43"
      ],
      "ipv6": "2a01:7e00::f03c:92ff:fe1a:9976/128",
      "image": "linode/debian10",
      "region": "eu-west",
      "specs": {
        "disk": 81920,
        "memory": 4096,
        "vcpus": 2,
        "gpus": 0,
        "transfer": 4000
      },
      "alerts": {
        "cpu": 180,
        "network_in": 10,
        "network_out": 10,
        "transfer_quota": 80,
        "io": 10000
      },
      "backups": {
        "enabled": false,
        "schedule": {
          "day": null,
          "window": null
        },
        "last_successful": null
      },
      "hypervisor": "kvm",
      "watchdog_enabled": true,
      "tags": [
        "monitoring"
      ]
    },
    {
      "id": 26837938,
      "label": "prometheus-linode-sd-exporter-3",
      "group": "",
      "status": "running",
      "created": "2021-05-12T04:20:11",
      "updated": "2021-05-12T04:20:11",
      "type": "g6-standard-1",
      "ipv4": [
        "192.53.120.25"
      ],
      "ipv6": "2600:3c04::f03c:92ff:fe1a:fb68/128",
      "image": "linode/ubuntu20.04",
      "region": "ca-central",
      "specs": {
        "disk": 51200,
        "memory": 2048,
        "vcpus": 1,
        "gpus": 0,
        "transfer": 2000
      },
      "alerts": {
        "cpu": 90,
        "network_in": 10,
        "network_out": 10,
        "transfer_quota": 80,
        "io": 10000
      },
      "backups": {
        "enabled": false,
        "schedule": {
          "day": null,
          "window": null
        },
        "last_successful": null
      },
      "hypervisor": "kvm",
      "watchdog_enabled": true,
      "tags": [
        "monitoring"
      ]
    },
    {
      "id": 26837992,
      "label": "prometheus-linode-sd-exporter-4",
      "group": "",
      "status": "running",
      "created": "2021-05-12T04:22:06",
      "updated": "2021-05-12T04:22:06",
      "type": "g6-nanode-1",
      "ipv4": [
        "66.228.47.103",
        "172.104.18.104",
        "192.168.148.94"
      ],
      "ipv6": "2600:3c03::f03c:92ff:fe1a:fb4c/128",
      "image": "linode/ubuntu20.04",
      "region": "us-east",
      "specs": {
        "disk": 25600,
        "memory": 1024,
        "vcpus": 1,
        "gpus": 0,
        "transfer": 1000
      },
      "alerts": {
        "cpu": 90,
        "network_in": 10,
        "network_out": 10,
        "transfer_quota": 80,
        "io": 10000
      },
      "backups": {
        "enabled": false,
        "schedule": {
          "day": null,
          "window": null
        },
        "last_successful": null
      },
      "hypervisor": "kvm",
      "watchdog_enabled": true,
      "tags": [
        "monitoring"
      ]
    }
  ],
  "page": 1,
  "pages": 1,
  "results": 4
}`,
		)
	})
}

// HandleLinodeNeworkingIPs mocks linode networking ips endpoint.
func (m *SDMock) HandleLinodeNeworkingIPs() {
	m.Mux.HandleFunc("/v4/networking/ips", func(w http.ResponseWriter, r *http.Request) {
		if r.Header.Get("Authorization") != fmt.Sprintf("Bearer %s", tokenID) {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}

		w.Header().Set("content-type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusOK)

		fmt.Fprint(w, `
{
  "page": 1,
  "pages": 1,
  "results": 13,
  "data": [
    {
      "address": "192.53.120.25",
      "gateway": "192.53.120.1",
      "subnet_mask": "255.255.255.0",
      "prefix": 24,
      "type": "ipv4",
      "public": true,
      "rdns": "li2216-25.members.linode.com",
      "linode_id": 26837938,
      "region": "ca-central"
    },
    {
      "address": "66.228.47.103",
      "gateway": "66.228.47.1",
      "subnet_mask": "255.255.255.0",
      "prefix": 24,
      "type": "ipv4",
      "public": true,
      "rdns": "li328-103.members.linode.com",
      "linode_id": 26837992,
      "region": "us-east"
    },
    {
      "address": "172.104.18.104",
      "gateway": "172.104.18.1",
      "subnet_mask": "255.255.255.0",
      "prefix": 24,
      "type": "ipv4",
      "public": true,
      "rdns": "li1832-104.members.linode.com",
      "linode_id": 26837992,
      "region": "us-east"
    },
    {
      "address": "192.168.148.94",
      "gateway": null,
      "subnet_mask": "255.255.128.0",
      "prefix": 17,
      "type": "ipv4",
      "public": false,
      "rdns": null,
      "linode_id": 26837992,
      "region": "us-east"
    },
    {
      "address": "192.168.170.51",
      "gateway": null,
      "subnet_mask": "255.255.128.0",
      "prefix": 17,
      "type": "ipv4",
      "public": false,
      "rdns": null,
      "linode_id": 26838044,
      "region": "us-east"
    },
    {
      "address": "96.126.108.16",
      "gateway": "96.126.108.1",
      "subnet_mask": "255.255.255.0",
      "prefix": 24,
      "type": "ipv4",
      "public": true,
      "rdns": "li365-16.members.linode.com",
      "linode_id": 26838044,
      "region": "us-east"
    },
    {
      "address": "45.33.82.151",
      "gateway": "45.33.82.1",
      "subnet_mask": "255.255.255.0",
      "prefix": 24,
      "type": "ipv4",
      "public": true,
      "rdns": "li1028-151.members.linode.com",
      "linode_id": 26838044,
      "region": "us-east"
    },
    {
      "address": "192.168.201.25",
      "gateway": null,
      "subnet_mask": "255.255.128.0",
      "prefix": 17,
      "type": "ipv4",
      "public": false,
      "rdns": null,
      "linode_id": 26838044,
      "region": "us-east"
    },
    {
      "address": "139.162.196.43",
      "gateway": "139.162.196.1",
      "subnet_mask": "255.255.255.0",
      "prefix": 24,
      "type": "ipv4",
      "public": true,
      "rdns": "li1359-43.members.linode.com",
      "linode_id": 26848419,
      "region": "eu-west"
    },
    {
      "address": "2600:3c04::f03c:92ff:fe1a:fb68",
      "gateway": "fe80::1",
      "subnet_mask": "ffff:ffff:ffff:ffff::",
      "prefix": 64,
      "type": "ipv6",
      "rdns": null,
      "linode_id": 26837938,
      "region": "ca-central",
      "public": true
    },
    {
      "address": "2600:3c03::f03c:92ff:fe1a:fb4c",
      "gateway": "fe80::1",
      "subnet_mask": "ffff:ffff:ffff:ffff::",
      "prefix": 64,
      "type": "ipv6",
      "rdns": null,
      "linode_id": 26837992,
      "region": "us-east",
      "public": true
    },
    {
      "address": "2600:3c03::f03c:92ff:fe1a:1382",
      "gateway": "fe80::1",
      "subnet_mask": "ffff:ffff:ffff:ffff::",
      "prefix": 64,
      "type": "ipv6",
      "rdns": null,
      "linode_id": 26838044,
      "region": "us-east",
      "public": true
    },
    {
      "address": "2a01:7e00::f03c:92ff:fe1a:9976",
      "gateway": "fe80::1",
      "subnet_mask": "ffff:ffff:ffff:ffff::",
      "prefix": 64,
      "type": "ipv6",
      "rdns": null,
      "linode_id": 26848419,
      "region": "eu-west",
      "public": true
    }
  ]
}`,
		)
	})
}

// HandleLinodeAccountEvents mocks linode the account/events endpoint.
func (m *SDMock) HandleLinodeAccountEvents() {
	m.Mux.HandleFunc("/v4/account/events", func(w http.ResponseWriter, r *http.Request) {
		if r.Header.Get("Authorization") != fmt.Sprintf("Bearer %s", tokenID) {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}

		if r.Header.Get("X-Filter") == "" {
			// This should never happen; if the client sends an events request without
			// a filter, cause it to fail. The error below is not a real response from
			// the API, but should aid in debugging failed tests.
			w.WriteHeader(http.StatusBadRequest)
			fmt.Fprint(w, `
{
	"errors": [
		{
			"reason": "Request missing expected X-Filter headers"
		}
	]
}`,
			)
			return
		}

		w.Header().Set("content-type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusOK)

		fmt.Fprint(w, `
{
	"data": [],
	"results": 0,
	"pages": 1,
	"page": 1
}`,
		)
	})
}
