/*
Copyright © 2025 cavaliba.com
*/
package poller

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"time"

	"github.com/spf13/viper"
)

type Monitor struct {
	Name              string        `json:"displayname"`
	Keyname           string        `json:"keyname"`
	Type              string        `json:"type"`
	Timeout           time.Duration `json:"-"`
	TimeoutMS         int           `json:"timeout"`
	HTTPURL           string        `json:"target"`
	HTTPCode          int           `json:"http_code"`
	HTTPPattern       string        `json:"http_pattern"`
	HTTPSSLVerify     bool          `json:"http_ssl_verify"`
	HTTPAllowRedirect bool          `json:"http_allow_redirect"`
}

type Worklist struct {
	Version  string    `json:"version"`
	Monitors []Monitor `json:"monitors"`
}

func GetWorklist() (Worklist, error) {

	var wl Worklist

	method := http.MethodGet
	url := viper.GetString("url") + "appstatus/worklist/"
	sslSkipVerify := viper.GetBool("ssl_skipverify")
	timeout := time.Duration(viper.GetInt("timeout")) * time.Millisecond

	transport := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: sslSkipVerify},
	}

	http_client := &http.Client{
		Transport: transport,
		Timeout:   timeout,
	}

	// Create request body reader if body is provided
	var bodyReader io.Reader
	// if target.body != "" {
	// 	bodyReader = strings.NewReader(target.body)
	// }

	// Create Request
	//req, err := http.NewRequestWithContext(ctx,
	req, err := http.NewRequest(
		method,
		url,
		bodyReader)

	if err != nil {
		return wl, errors.New("invalid server parameters")
	}

	var header = viper.GetString("client_id") + " " + viper.GetString("client_secret")
	req.Header.Add("X-Cavaliba-Key", header)

	// Set Content-Type header, default to application/json if not specified
	//var contentType := "application/json"
	//req.Header.Add("Content-Type", contentType)

	// start := time.Now()

	// PERFORM REQUEST
	resp, err := http_client.Do(req)
	if err != nil {
		return wl, errors.New("no answer from server")
	}
	defer resp.Body.Close()

	// Check HTTP status code
	if resp.StatusCode == 401 {
		return wl, fmt.Errorf("denied")
	}
	if resp.StatusCode == 404 {
		return wl, fmt.Errorf("not found")
	}
	if resp.StatusCode == 405 {
		return wl, fmt.Errorf("method not allowed")
	}
	if resp.StatusCode != 200 {
		return wl, fmt.Errorf("http error from server (status: %d)", resp.StatusCode)
	}

	// Read response body
	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return wl, errors.New("can't read server answer")
	}

	verbose := viper.GetBool("verbose")
	if verbose {
		fmt.Println("")
		fmt.Println("Received Worklist from API")
		fmt.Println("==========================")
		fmt.Printf("JSON Response:\n")

		// Pretty print JSON for readability
		var prettyJSON bytes.Buffer
		err := json.Indent(&prettyJSON, bodyBytes, "", "  ")
		if err == nil {
			fmt.Println(prettyJSON.String())
		} else {
			fmt.Println(string(bodyBytes))
		}
		fmt.Println("==========================")
	}

	// Unpack JSON worklist
	// Expected format:
	// 	{
	//   "version": "1234567890",
	//   "monitors": [
	//     {
	//       "keyname": "www_cavaliba",
	//       "displayname": "www.cavaliba.com",
	//       "type": "HTTP",
	//       "is_enabled": true,
	//       "timeout": 2000,
	//       "target": "https://www.cavaliba.com/",
	//       "http_code": 200,
	//       "http_ssl_verify": true,
	//       "http_allow_redirect": true,
	//       "http_pattern": "",
	//       "http_pattern_reject": ""
	//     }
	//   ]
	// }

	err = json.Unmarshal(bodyBytes, &wl)
	if err != nil {
		return wl, fmt.Errorf("invalid JSON from server: %w", err)
	}

	// Convert TimeoutMS (int) to Timeout (time.Duration) for each monitor
	for i := range wl.Monitors {
		wl.Monitors[i].Timeout = time.Duration(wl.Monitors[i].TimeoutMS) * time.Millisecond
	}

	// Manual example monitors (for testing without API)
	// wl.Version = "Test"
	// wl.Monitors = append(wl.Monitors, Monitor{
	// 	Name:     "monitor1",
	// 	URL:      "https://www.cavaliba.com/",
	// 	HTTPCode: 200,
	// 	Pattern:  "cavaliba",
	// 	Timeout:  time.Duration(500) * time.Millisecond,
	// })
	// wl.Monitors = append(wl.Monitors, Monitor{
	// 	Name:     "monitor2",
	// 	URL:      "https://www.cavaliba.com/download/",
	// 	HTTPCode: 200,
	// 	Pattern:  "Directory",
	// 	Timeout:  time.Duration(500) * time.Millisecond,
	// })
	// wl.Monitors = append(wl.Monitors, Monitor{
	// 	Name:     "monitor3",
	// 	URL:      "https://www.apache.org/",
	// 	HTTPCode: 200,
	// 	Pattern:  "Community",
	// 	Timeout:  time.Duration(500) * time.Millisecond,
	// })

	return wl, nil

}

// PrintWorklist displays the worklist information in a readable format
func PrintWorklist(wl Worklist) {
	verbose := viper.GetBool("verbose")

	fmt.Printf("Worklist\n")
	fmt.Printf("========\n")
	fmt.Printf("Version: %s\n", wl.Version)
	fmt.Printf("Monitors: %d\n\n", len(wl.Monitors))

	for i, monitor := range wl.Monitors {
		fmt.Printf("[%d] - %-8s - %-20s - %-30s - %s\n", i+1, monitor.Type, monitor.Keyname, monitor.Name, monitor.HTTPURL)

		if verbose {
			fmt.Printf("      HTTP Code: %d\n", monitor.HTTPCode)
			fmt.Printf("      Pattern: %s\n", monitor.HTTPPattern)
			fmt.Printf("      Timeout: %v\n", monitor.Timeout)
			fmt.Printf("      SSL Verify: %v\n", monitor.HTTPSSLVerify)
			fmt.Printf("      Allow Redirect: %v\n", monitor.HTTPAllowRedirect)
		}
		fmt.Println()
	}
}
