package main

import (
	"context"
	"flag"
	"fmt"
	"os"
	"strings"
	"time"
)

const (
	defaultForecastTTL = 10 * time.Minute
)

func main() {
	if err := run(); err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}
}

func run() error {
	var (
		search       string
		includeDesc  bool
		prettyOutput bool
		temperatureU string
		clearCache   bool
		refresh      bool
		iconTest     bool
	)

	flag.StringVar(&search, "s", "", "Search location (e.g. \"Somerville, MA\")")
	flag.StringVar(&search, "search", "", "Search location (e.g. \"Somerville, MA\")")
	flag.BoolVar(&includeDesc, "d", false, "Include forecast description text")
	flag.BoolVar(&includeDesc, "desc", false, "Include forecast description text")
	flag.BoolVar(&prettyOutput, "pretty", false, "Enable NerdFont icons")
	flag.BoolVar(&prettyOutput, "p", false, "Enable NerdFont icons")
	flag.StringVar(&temperatureU, "u", "F", "Temperature unit (F or C)")
	flag.StringVar(&temperatureU, "units", "F", "Temperature unit (F or C)")
	flag.BoolVar(&clearCache, "clear-cache", false, "Clear cached location and forecast data")
	flag.BoolVar(&clearCache, "c", false, "Clear cached location and forecast data")
	flag.BoolVar(&refresh, "refresh", false, "Force refresh forecast data")
	flag.BoolVar(&refresh, "r", false, "Force refresh forecast data")
	flag.BoolVar(&iconTest, "icon-test", false, "Print all icons used by the program")
	flag.BoolVar(&iconTest, "i", false, "Print all icons used by the program")
	flag.Parse()

	ua, err := buildUserAgent()
	if err != nil {
		return err
	}

	temperatureU = strings.ToUpper(strings.TrimSpace(temperatureU))
	if temperatureU == "" {
		temperatureU = "F"
	}
	if temperatureU != "F" && temperatureU != "C" {
		return fmt.Errorf("invalid unit: %s", temperatureU)
	}

	cacheDir, err := cacheRoot()
	if err != nil {
		return err
	}

	cache := NewCache(cacheDir)
	ctx := context.Background()

	if iconTest {
		printIconTest()
		return nil
	}

	if clearCache {
		if err := cache.Clear(); err != nil {
			return err
		}
		return nil
	}

	var loc Location
	if search != "" {
		results, err := SearchLocations(ctx, search, ua)
		if err != nil {
			return err
		}
		loc, err = SelectLocation(results)
		if err != nil {
			return err
		}
		if err := cache.SaveLocation(search, loc); err != nil {
			return err
		}
	} else {
		var ok bool
		loc, ok, err = cache.LoadLocation()
		if err != nil {
			return err
		}
		if !ok {
			return fmt.Errorf("no cached location found; use -s to set a location")
		}
	}

	client := NewNWSClient(ua)
	var period ForecastPeriod
	if refresh {
		var err error
		period, err = client.FetchForecast(ctx, loc, temperatureU)
		if err != nil {
			return err
		}
		if err := cache.SaveForecast(loc, temperatureU, period); err != nil {
			return err
		}
	} else {
		var err error
		var fromCache bool
		period, fromCache, err = cache.LoadForecast(loc, temperatureU, defaultForecastTTL)
		if err != nil {
			return err
		}
		if !fromCache {
			period, err = client.FetchForecast(ctx, loc, temperatureU)
			if err != nil {
				return err
			}
			if err := cache.SaveForecast(loc, temperatureU, period); err != nil {
				return err
			}
		}
	}

	line := FormatOutput(loc, period, includeDesc, prettyOutput)
	fmt.Println(line)
	return nil
}
