package main

import (
  "context"
  "embed"
  "encoding/json"
  "net/http"
  "net/url"
  "os"
  "runtime"
  "strings"
  "time"

  "log"

  "github.com/mrusme/superhighway84/cache"
  "github.com/mrusme/superhighway84/config"
  "github.com/mrusme/superhighway84/database"
  "github.com/mrusme/superhighway84/models"
  "github.com/mrusme/superhighway84/tui"
  "go.uber.org/zap"
)

//go:embed superhighway84.jpeg
var EMBEDFS embed.FS
var version = "v0.0.0"

func NewLogger(filename string) (*zap.Logger, error) {
  if runtime.GOOS == "windows" {
    zap.RegisterSink("winfile", func(u *url.URL) (zap.Sink, error) {
      return os.OpenFile(u.Path[1:], os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
    })
  }

  cfg := zap.NewDevelopmentConfig()
  if runtime.GOOS == "windows" {
    cfg.OutputPaths = []string{
      "stdout",
      "winfile:///" + filename,
    }
  } else {
    cfg.OutputPaths = []string{
      filename,
    }
  }

  return cfg.Build()
}

func main() {
  ctx, cancel := context.WithCancel(context.Background())
  defer cancel()

  log.Println("loading configuration ...")
  cfg, err := config.LoadConfig()
  if err != nil {
    log.Panicln(err)
  }
  if cfg.WasSetup() == false {
    cfg.Setup()
  }

  log.Println("initializing logger ...")
  logger, err := NewLogger(cfg.Logfile)
  if err != nil {
    log.Panicln(err)
  }

  log.Println("initializing cache ...")
  cch, err := cache.NewCache(cfg.ProgramCachePath)
  if err != nil {
    log.Panicln(err)
  }
  defer cch.Close()

  var articles []*models.Article
  var articlesRoots []*models.Article

  log.Println("initializing TUI and loading database, please wait ...")
  TUI := tui.Init(&EMBEDFS, cfg, cch, logger)
  TUI.SetVersion(strings.TrimLeft(version, "v"), strings.TrimLeft(getLatestVersion(), "v") )

  TUI.ArticlesDatasource = &articles
  TUI.ArticlesRoots = &articlesRoots

  log.Println("initializing database ...")
  db, err := database.NewDatabase(ctx, cfg.ConnectionString, cfg.DatabaseCachePath, cch, logger)
  if err != nil {
    log.Panicln(err)
  }
  defer db.Disconnect()

  TUI.CallbackRefreshArticles = func() (error) {
    articles, articlesRoots, err = db.ListArticles()
    if err != nil {
      logger.Error("%s", zap.Error(err))
    }
    return err
  }
  TUI.CallbackSubmitArticle = func(article *models.Article) (error) {
    err := db.SubmitArticle(article)
    if err != nil {
      logger.Error("%s", zap.Error(err))
    }
    return err
  }

  log.Println("connecting database ...")
  err = db.Connect(func(address string) {
    TUI.Meta["myID"] = db.GetOwnID()
    TUI.Meta["myPubKey"] = db.GetOwnPubKey()

    TUI.Views["mainscreen"].(*tui.Mainscreen).SetFooter(address)
    articles, articlesRoots, _ = db.ListArticles()


    time.Sleep(time.Second * 2)
    TUI.SetView("mainscreen", true)

    TUI.RefreshData()
    TUI.Refresh()
    TUI.App.Draw()
  })
  if err != nil {
    log.Panicln(err)
  }


  go func() {
    peers := 0
    for {
      bw := db.IPFSNode.Reporter.GetBandwidthTotals()
      connections, err := db.IPFSCoreAPI.Swarm().Peers(context.Background())
      if err == nil {
        peers = len(connections)
      } else {
        logger.Error("%s", zap.Error(err))
      }
      TUI.SetStats(int64(peers), int64(bw.RateIn), int64(bw.RateOut), bw.TotalIn , bw.TotalOut)
      time.Sleep(time.Second * 5)
    }
  }()

  TUI.Launch()
}


func getLatestVersion() (string) {
  var client = &http.Client{Timeout: 10 * time.Second}
  r, err := client.Get(
    "https://api.github.com/repos/mrusme/superhighway84/releases/latest",
  )
  if err != nil {
      return version
  }
  defer r.Body.Close()
  var result map[string]interface{}
  json.NewDecoder(r.Body).Decode(&result)

  if val, exist := result["tag_name"]; exist == true {
    return val.(string)
  }
  return version
}

