package internal

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

	"github.com/yusing/go-proxy/internal/utils"
)

type GitHubContents struct { //! keep this, may reuse in future
	Type string `json:"type"`
	Path string `json:"path"`
	Name string `json:"name"`
	Sha  string `json:"sha"`
	Size int    `json:"size"`
}

const (
	iconsCachePath = "/tmp/icons_cache.json"
	updateInterval = 1 * time.Hour
)

func ListAvailableIcons() ([]string, error) {
	owner := "walkxcode"
	repo := "dashboard-icons"
	ref := "main"

	var lastUpdate time.Time

	icons := make([]string, 0)
	info, err := os.Stat(iconsCachePath)
	if err == nil {
		lastUpdate = info.ModTime().Local()
	}
	if time.Since(lastUpdate) < updateInterval {
		err := utils.LoadJSON(iconsCachePath, &icons)
		if err == nil {
			return icons, nil
		}
	}

	contents, err := getRepoContents(http.DefaultClient, owner, repo, ref, "")
	if err != nil {
		return nil, err
	}
	for _, content := range contents {
		if content.Type != "dir" {
			icons = append(icons, content.Path)
		}
	}
	err = utils.SaveJSON(iconsCachePath, &icons, 0o644)
	if err != nil {
		log.Print("error saving cache", err)
	}
	return icons, nil
}

func getRepoContents(client *http.Client, owner string, repo string, ref string, path string) ([]GitHubContents, error) {
	req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("https://api.github.com/repos/%s/%s/contents/%s?ref=%s", owner, repo, path, ref), nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Accept", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var contents []GitHubContents
	err = json.Unmarshal(body, &contents)
	if err != nil {
		return nil, err
	}

	filesAndDirs := make([]GitHubContents, 0)
	for _, content := range contents {
		if content.Type == "dir" {
			subContents, err := getRepoContents(client, owner, repo, ref, content.Path)
			if err != nil {
				return nil, err
			}
			filesAndDirs = append(filesAndDirs, subContents...)
		} else {
			filesAndDirs = append(filesAndDirs, content)
		}
	}

	return filesAndDirs, nil
}