package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/bcurren/go-ssdp"
	"imuslab.com/zoraxy/mod/dynamicproxy"
	"imuslab.com/zoraxy/mod/ipscan"
	"imuslab.com/zoraxy/mod/mdns"
	"imuslab.com/zoraxy/mod/uptime"
	"imuslab.com/zoraxy/mod/utils"
)

/*
	Proxy Utils
*/
//Check if site support TLS
func HandleCheckSiteSupportTLS(w http.ResponseWriter, r *http.Request) {
	targetURL, err := utils.PostPara(r, "url")
	if err != nil {
		utils.SendErrorResponse(w, "invalid url given")
		return
	}

	httpsUrl := fmt.Sprintf("https://%s", targetURL)
	httpUrl := fmt.Sprintf("http://%s", targetURL)

	client := http.Client{Timeout: 5 * time.Second}

	resp, err := client.Head(httpsUrl)
	if err == nil && resp.StatusCode == http.StatusOK {
		js, _ := json.Marshal("https")
		utils.SendJSONResponse(w, string(js))
		return
	}

	resp, err = client.Head(httpUrl)
	if err == nil && resp.StatusCode == http.StatusOK {
		js, _ := json.Marshal("http")
		utils.SendJSONResponse(w, string(js))
		return
	}

	utils.SendErrorResponse(w, "invalid url given")
}

/*
	Statistic Summary
*/

//Handle conversion of statistic daily summary to country summary
func HandleCountryDistrSummary(w http.ResponseWriter, r *http.Request) {
	requestClientCountry := map[string]int{}
	statisticCollector.DailySummary.RequestClientIp.Range(func(key, value interface{}) bool {
		//Get this client country of original
		clientIp := key.(string)
		//requestCount := value.(int)

		ci, err := geodbStore.ResolveCountryCodeFromIP(clientIp)
		if err != nil {
			return true
		}

		isoCode := ci.CountryIsoCode
		if isoCode == "" {
			//local or reserved addr
			isoCode = "local"
		}
		uc, ok := requestClientCountry[isoCode]
		if !ok {
			//Create the counter
			requestClientCountry[isoCode] = 1
		} else {
			requestClientCountry[isoCode] = uc + 1
		}
		return true
	})

	js, _ := json.Marshal(requestClientCountry)
	utils.SendJSONResponse(w, string(js))
}

/*
	Up Time Monitor
*/
//Generate uptime monitor targets from reverse proxy rules
func GetUptimeTargetsFromReverseProxyRules(dp *dynamicproxy.Router) []*uptime.Target {
	subds := dp.GetSDProxyEndpointsAsMap()
	vdirs := dp.GetVDProxyEndpointsAsMap()

	UptimeTargets := []*uptime.Target{}
	for subd, target := range subds {
		url := "http://" + target.Domain
		protocol := "http"
		if target.RequireTLS {
			url = "https://" + target.Domain
			protocol = "https"
		}
		UptimeTargets = append(UptimeTargets, &uptime.Target{
			ID:       subd,
			Name:     subd,
			URL:      url,
			Protocol: protocol,
		})
	}

	for vdir, target := range vdirs {
		url := "http://" + target.Domain
		protocol := "http"
		if target.RequireTLS {
			url = "https://" + target.Domain
			protocol = "https"
		}
		UptimeTargets = append(UptimeTargets, &uptime.Target{
			ID:       vdir,
			Name:     "*" + vdir,
			URL:      url,
			Protocol: protocol,
		})
	}

	return UptimeTargets
}

//Handle rendering up time monitor data
func HandleUptimeMonitorListing(w http.ResponseWriter, r *http.Request) {
	if uptimeMonitor != nil {
		uptimeMonitor.HandleUptimeLogRead(w, r)
	} else {
		http.Error(w, "500 - Internal Server Error", http.StatusInternalServerError)
		return
	}
}

//Handle listing current registered mdns nodes
func HandleMdnsListing(w http.ResponseWriter, r *http.Request) {
	js, _ := json.Marshal(previousmdnsScanResults)
	utils.SendJSONResponse(w, string(js))
}

func HandleMdnsScanning(w http.ResponseWriter, r *http.Request) {
	domain, err := utils.PostPara(r, "domain")
	var hosts []*mdns.NetworkHost
	if err != nil {
		//Search for arozos node
		hosts = mdnsScanner.Scan(30, "")
		previousmdnsScanResults = hosts
	} else {
		//Search for other nodes
		hosts = mdnsScanner.Scan(30, domain)
	}

	js, _ := json.Marshal(hosts)
	utils.SendJSONResponse(w, string(js))
}

//handle ip scanning
func HandleIpScan(w http.ResponseWriter, r *http.Request) {
	cidr, err := utils.PostPara(r, "cidr")
	if err != nil {
		//Ip range mode
		start, err := utils.PostPara(r, "start")
		if err != nil {
			utils.SendErrorResponse(w, "missing start ip")
			return
		}

		end, err := utils.PostPara(r, "end")
		if err != nil {
			utils.SendErrorResponse(w, "missing end ip")
			return
		}

		discoveredHosts, err := ipscan.ScanIpRange(start, end)
		if err != nil {
			utils.SendErrorResponse(w, err.Error())
			return
		}

		js, _ := json.Marshal(discoveredHosts)
		utils.SendJSONResponse(w, string(js))
	} else {
		//CIDR mode
		discoveredHosts, err := ipscan.ScanCIDRRange(cidr)
		if err != nil {
			utils.SendErrorResponse(w, err.Error())
			return
		}

		js, _ := json.Marshal(discoveredHosts)
		utils.SendJSONResponse(w, string(js))
	}
}

//Handle SSDP discovery
func HandleSsdpDiscovery(w http.ResponseWriter, r *http.Request) {
	responses, err := ssdp.Search("ssdp:discover", 10*time.Second)
	log.Println(responses, err)
	if err != nil {
		return
	}

	for _, response := range responses {
		// Do something with the response you discover
		fmt.Println(response)
	}
}