package icapclient

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/egirna/icap"
)

var (
	stop = make(chan os.Signal, 1)
	port = 1344
)

const (
	previewBytes      = 24
	goodFileDetectStr = "GOOD FILE"
	badFileDetectStr  = "BAD FILE"
	goodURL           = "http://goodifle.com"
	badURL            = "http://badfile.com"
)

func startTestServer() {
	icap.HandleFunc("/respmod", respmodHandler)
	icap.HandleFunc("/reqmod", reqmodHandler)

	log.Println("Starting ICAP test server...")

	signal.Notify(stop, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT)

	go func() {
		if err := icap.ListenAndServe(fmt.Sprintf(":%d", port), nil); err != nil {
			log.Println("Failed to start ICAP test server: ", err.Error())
			return
		}
	}()

	time.Sleep(5 * time.Millisecond)

	log.Printf("ICAP test server is running on localhost:%d\n...\n", port)
	<-stop

	log.Println("ICAP test server is shut down!")
}

func stopTestServer() {
	stop <- syscall.SIGKILL
}

func respmodHandler(w icap.ResponseWriter, req *icap.Request) {
	h := w.Header()
	h.Set("ISTag", "ICAP-TEST")
	h.Set("Service", "ICAP-TEST-SERVICE")

	switch req.Method {
	case "OPTIONS":
		h.Set("Methods", "RESPMOD")
		h.Set("Allow", "204")
		if previewBytes > 0 {
			h.Set("Preview", strconv.Itoa(previewBytes))
		}
		h.Set("Transfer-Preview", "*")
		w.WriteHeader(http.StatusOK, nil, false)
	case "RESPMOD":
		defer req.Response.Body.Close()

		if val, exist := req.Header["Allow"]; !exist || (len(val) > 0 && val[0] != "204") {
			w.WriteHeader(http.StatusNoContent, nil, false)
			return
		}

		buf := &bytes.Buffer{}

		if _, err := io.Copy(buf, req.Response.Body); err != nil {
			log.Println("Failed to copy the response body to buffer: ", err.Error())
			w.WriteHeader(http.StatusNoContent, nil, false)
			return
		}

		status := 0
		if strings.Contains(buf.String(), goodFileDetectStr) {
			status = http.StatusNoContent
		}

		if strings.Contains(buf.String(), badFileDetectStr) {
			status = http.StatusOK
		}

		w.WriteHeader(status, nil, false)

	}
}

func reqmodHandler(w icap.ResponseWriter, req *icap.Request) {
	h := w.Header()
	h.Set("ISTag", "ICAP-TEST")
	h.Set("Service", "ICAP-TEST-SERVICE")

	switch req.Method {
	case "OPTIONS":
		h.Set("Methods", "REQMOD")
		h.Set("Allow", "204")
		if previewBytes > 0 {
			h.Set("Preview", strconv.Itoa(previewBytes))
		}
		h.Set("Transfer-Preview", "*")
		w.WriteHeader(http.StatusOK, nil, false)
	case "REQMOD":

		if val, exist := req.Header["Allow"]; !exist || (len(val) > 0 && val[0] != "204") {
			w.WriteHeader(http.StatusNoContent, nil, false)
			return
		}

		fileURL := req.Request.RequestURI

		status := 0
		if fileURL == goodURL {
			status = http.StatusNoContent
		}

		if fileURL == badURL {
			status = http.StatusOK
		}

		w.WriteHeader(status, nil, false)

	}
}

func testServerRunning() bool {
	lstnr, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
	if err != nil {
		return true
	}
	lstnr.Close()
	return false
}
