package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"strings"

	"github.com/beego/x2j"
)

// https://zetcode.com/golang/getpostrequest/ post_req_form.go
func Post(where string) *http.Response {
	resp, err := http.PostForm(where, nil)
	if err != nil {
		log.Printf("POST got non 200 code, %v", err)
		// Catch what error it is, if it's a no access to device try a etherwake
		return nil
	}
	return resp
}

/*func ListenToRequests(ln *net.UDPConn, data *string) {
	done := false
	do_send := true
	for !done {
		buffer := make([]byte, 1024) // 1k
		ln.SetReadDeadline(time.Now().Add(3 * time.Second))
		for !done {
			b, _, err := ln.ReadFromUDP(buffer)
			if b > 0 {
				str := string(buffer[0:])
				*data += str
			}
			if err != nil {
				if _, ok := err.(net.Error); !ok {
					log.Print(err)
					done = true
				}
			}

			if do_send {
				err = PostFind()
				if err != nil {
					log.Printf("POST Find returned %v", err)
				}
				do_send = false
			}
		}
	}
}*/

/*
func PostFind() {
	file, err := os.ReadFile("finder.txt")
	if err != nil {
		log.Print(err)
	}
	addr, err := net.ResolveUDPAddr("udp", "239.255.255.250:1900")
	if err != nil {
		log.Print(err)
	}
	conn, err := net.DialUDP("udp", nil, addr)
	if err != nil {
		log.Print(err)
	}
	defer conn.Close()
	conn.Write(file)
	log.Println("Posted Request for devices")
}

func GetFind(data *[]string) {

	addr, err := net.ResolveUDPAddr("udp", ":1900")
	if err != nil {
		log.Printf("GET Find failed getting port 1900, %v", err)
		return
	}
	fmt.Printf("Listening on %s\r\n", addr.String())
	ln, err := net.ListenUDP("udp", addr)
	if err != nil {
		log.Printf("GET Find started listener for 1900, %v", err)
		return
	}

	var list []string
	buffer := make([]byte, 1024) // 1k
	defer ln.Close()
	ln.SetReadDeadline(time.Now().Add(3 * time.Second))
	for {
		n, adr, err := ln.ReadFromUDP(buffer)
		str := string(buffer[0:n])
		fmt.Printf("Got '%s' from %s\r\n", str, adr.String())
		if err != nil {
			log.Println(err)
			break
		}
		list = append(list, adr.String())
	}
	*data = list
}
*/

func Get(where string) *http.Response {
	resp, err := http.Get(where)
	if err != nil {
		log.Printf("GET got non 200 code, %v", err)
		return nil
	} else {
		return resp
	}
}

// https://developer.roku.com/docs/developer-program/debugging/external-control-api.md#keypress-key-values codes
func KeyPress(ip, command string) string {
	return fmt.Sprintf("http://%s:8060/keypress/%s", ip, command)
}

// https://developer.roku.com/docs/developer-program/debugging/external-control-api.md#general-ecp-commands
func Query(ip, what string) string {
	return fmt.Sprintf("http://%s:8060/query/%s", ip, what)
}

func PerformKey(ip, command string) bool {
	r := Post(KeyPress(ip, command))
	if r == nil {
		return false
	}
	defer r.Body.Close()
	return true
}

func GetQuery(ip, command string) []byte {
	var resp *http.Response = Get(Query(ip, command))
	if resp == nil {
		return nil
	}
	var body []byte
	var err error
	body, err = io.ReadAll(resp.Body)
	if err != nil {
		log.Printf("Reading from body got error, %v", err)
	}
	defer resp.Body.Close()
	return body
}

func GetCurrentPlay(ip string) *MediaPlayer {
	var resp []byte = GetQuery(ip, "media-player")
	var mp MediaPlayer
	var err error = x2j.Unmarshal(resp, &mp)
	if err != nil {
		log.Printf("Error occurred processing XML, %v", err)
	}
	return &mp
}

func ObtainDeviceInfo(ip string) *DeviceInfo {
	var resp []byte = GetQuery(ip, "device-info")
	var di DeviceInfo
	var err error = x2j.Unmarshal(resp, &di)
	if err != nil {
		log.Printf("Error occurred processing XML, %v", err)
	}
	return &di
}

// Returns a map of device-infos
func GetDeviceInfo(ip string) *DeviceInfo {
	var di *DeviceInfo = ObtainDeviceInfo(ip)
	/*keys := glom.GetPossible(dev)
	for _, key := range keys {
		log.Printf("%s = %v", key, dev[key])
	}*/
	return di
}

func GetDevices(wake_on_lan map[string]string) (*[]string, map[string]string) {
	var str []string
	resp := strings.Split(PostFind(), "\n")
	//fmt.Printf("Processing %d lines\n", len(resp))
	ip := ""
	for _, line := range resp {
		if strings.Contains(line, "LOCATION") {
			st := strings.ReplaceAll(line, "LOCATION: http://", "")
			st = strings.ReplaceAll(st, ":8060/", "")
			st = strings.ReplaceAll(st, "\r", "")
			//fmt.Printf("IP='%s'", st)
			str = append(str, st)
			ip = st
		} else if strings.Contains(line, "WAKEUP") {
			st := strings.ReplaceAll(line, "WAKEUP: MAC=", "")
			st = strings.ReplaceAll(st, ";Timeout=10", "")
			st = strings.ReplaceAll(st, "\r", "")
			//fmt.Printf("IP='%s' MAC='%s'", ip, st)
			wake_on_lan[ip] = st
		}
	}
	return &str, wake_on_lan
}

func DebugInfo(ip string) string {
	// Query the current playing thing, and get the tv channels
	var mp *MediaPlayer = GetCurrentPlay(ip)
	var name string
	var id string
	/*r1 := GetQuery(ip, "tv-channels")
	chan_name, _ := glom.Glom(r1, "tv-channels.channel.name")
	chan_phy_id, _ := glom.Glom(r1, "tv-channels.channel.physical-channel")
	chan_number, _ := glom.Glom(r1, "tv-channels.channel.number")*/
	if mp.Plugin.Name == "" && mp.Plugin.Id == 0 {
		name = "TV"
		id = "No Connection"
	} else {
		name = mp.Plugin.Name
		id = fmt.Sprintf("%d", mp.Plugin.Id)
	}

	// Debug print
	fmt.Printf("Name: %v (%v)\r\n", name, id)
	//fmt.Printf("Channel: %v (%v / %v)\r\n", chan_name, chan_phy_id, chan_number)
	return fmt.Sprintf("%v (%v)", name, id)
}
