package command

import (
	"context"
	"fmt"
	"net/url"
	"os"
	"strings"

	"github.com/StevanFreeborn/gator/internal/database"
	"github.com/StevanFreeborn/gator/internal/state"
	"golang.org/x/term"
)

func normalizeFeedURL(raw string) (string, error) {
	u, err := url.Parse(raw)

	if err != nil {
		return "", err
	}

	u.Scheme = strings.ToLower(u.Scheme)
	u.Host = strings.ToLower(u.Host)

	if (u.Scheme == "http" && u.Port() == "80") || (u.Scheme == "https" && u.Port() == "443") {
		u.Host = u.Hostname()
	}

	if len(u.Path) > 1 {
		u.Path = strings.TrimSuffix(u.Path, "/")
	}

	u.Fragment = ""

	return u.String(), nil
}

func resolveFeedByNameOrURL(s *state.State, identifier string) (database.Feed, error) {
	if strings.TrimSpace(identifier) == "" {
		return database.Feed{}, fmt.Errorf("Feed identifier cannot be empty")
	}

	feeds, err := s.Database.GetAllFeeds(context.Background())

	if err != nil {
		return database.Feed{}, fmt.Errorf("Failed to load feeds")
	}

	var matches []database.Feed

	for _, feed := range feeds {
		if strings.EqualFold(feed.Name, identifier) {
			matches = append(matches, feed)
		}
	}

	if len(matches) == 1 {
		return matches[0], nil
	}

	if len(matches) > 1 {
		return database.Feed{}, fmt.Errorf("Multiple feeds match name '%s'; use a url instead", identifier)
	}

	normalizedURL, err := normalizeFeedURL(identifier)

	if err != nil {
		return database.Feed{}, fmt.Errorf("No feed found matching name or url '%s'", identifier)
	}

	feed, err := s.Database.GetFeedByUrl(context.Background(), normalizedURL)

	if err != nil {
		return database.Feed{}, fmt.Errorf("No feed found matching name or url '%s'", identifier)
	}

	return feed, nil
}

func enableKeypressExit(cancel context.CancelFunc) (func(), error) {
	oldState, err := term.MakeRaw(int(os.Stdin.Fd()))

	if err != nil {
		return nil, fmt.Errorf("Failed to enable raw mode: %v", err)
	}

	go func() {
		buf := make([]byte, 1)

		for {
			n, err := os.Stdin.Read(buf)

			if err != nil || n == 0 {
				return
			}

			if buf[0] == 'q' || buf[0] == 'Q' || buf[0] == 3 {
				cancel()
				return
			}
		}
	}()

	return func() {
		term.Restore(int(os.Stdin.Fd()), oldState)
	}, nil
}
