package src

import (
  "text/template"
  "fmt"
  "net/http"
  "strings"
  "strconv"
  "time"
  "os"
  "encoding/json"

  "gitler.moe/suwako/hozonsite/common"
  "gitler.moe/suwako/goliblocale"
)

type (
  Page struct {
    Err, Lan, Ver, Ves, Url, Body string
    i18n map[string]string
    Ext []Exist // 既に存在する場合
  }
  Stat struct { // APIのみ
    Url, Ver string
  }
  Exist struct {
    Date, Url string
  }
)

var ftmpl []string
var data *Page

func (p Page) T (key string) string {
  return p.i18n[key]
}

// 言語設定、デフォルト=ja
func initloc (r *http.Request) string {
  supportedLanguages := map[string]bool{
    "ja": true,
    "en": true,
  }

  cookie, err := r.Cookie("lang")
  if err != nil {
    return "ja"
  }

  if _, ok := supportedLanguages[cookie.Value]; ok {
    return cookie.Value
  } else {
    return "ja"
  }
}

func tspath (p string) string {
  pc := strings.Split(p, "/")

  for i := len(pc) - 1; i >= 0; i-- {
    if _, err := strconv.Atoi(pc[i]); err == nil {
      return pc[i]
    }
  }

  return ""
}

func handleStatic(path string, cnf Config, w http.ResponseWriter, r *http.Request) {
    if !strings.HasSuffix(path, ".css") &&
       !strings.HasSuffix(path, ".png") &&
       !strings.HasSuffix(path, ".jpeg") &&
       !strings.HasSuffix(path, ".jpg") &&
       !strings.HasSuffix(path, ".webm") &&
       !strings.HasSuffix(path, ".gif") &&
       !strings.HasSuffix(path, ".js") {
    http.NotFound(w, r)
    return
  }

  fpath := cnf.Datapath + "/archive/" + path
  http.ServeFile(w, r, fpath)
}

func handlePost(w http.ResponseWriter, r *http.Request, cnf Config) {
  err := r.ParseForm()
  if err != nil {
    fmt.Println(err)
    http.Redirect(w, r, "/", http.StatusSeeOther)
    return
  }

  // 言語変更
  if lang := r.PostFormValue("lang"); lang != "" {
    http.SetCookie(
      w,
      &http.Cookie{Name: "lang", Value: lang, MaxAge: 31536000, Path: "/"},
    )
    http.Redirect(w, r, "/", http.StatusSeeOther)
    return
  }

  var exist []string
  langu := initloc(r)
  i18n, err := goliblocale.GetLocale(cnf.Webpath + "/locale/" + langu)
  if err != nil {
    fmt.Printf("liblocaleエラー:%v", err)
    return
  }

  if r.PostForm.Get("hozonsite") == "" {
    data.Err = i18n["errfusei"]
    ftmpl[0] = cnf.Webpath + "/view/404.html"
    return
  }

  url := r.PostForm.Get("hozonsite")
  // HTTPかHTTPSじゃない場合
  if !Checkprefix(url) {
    data.Err = i18n["errfuseiurl"]
    ftmpl[0] = cnf.Webpath + "/view/404.html"
    return
  }

  eurl := Stripurl(url)
  exist = Checkexist(eurl, cnf.Datapath)
  if len(exist) == 0 || r.PostForm.Get("agree") == "1" {
    path := Mkdirs(eurl, cnf.Datapath)
    Getpage(url, path)
    Scanpage(path, eurl, cnf.Datapath)
    http.Redirect(
      w,
      r,
      cnf.Domain + strings.Replace(path, cnf.Datapath, "", 1),
      http.StatusSeeOther,
    )
    return
  }

  ftmpl[0] = cnf.Webpath + "/view/check.html"
  data.Url = url
  var existing []Exist
  e := Exist{}
  for _, ex := range exist {
    ti, err := strconv.ParseInt(tspath(ex), 10, 64)
    if err != nil {
      fmt.Println(err)
      http.Redirect(w, r, "/", http.StatusSeeOther)
      return
    }

    t := time.Unix(ti, 0)
    e.Date = t.Format("2006年01月02日 15:04:05")
    e.Url = strings.Replace(ex, cnf.Datapath, cnf.Domain, 1)
    existing = append(existing, e)
  }

  data.Ext = existing
}

// ホームページ
func siteHandler (cnf Config) func (http.ResponseWriter, *http.Request) {
  return func (w http.ResponseWriter, r *http.Request) {
    ftmpl = []string{
      cnf.Webpath + "/view/index.html",
      cnf.Webpath + "/view/header.html",
      cnf.Webpath + "/view/footer.html",
    }

    version := common.GetVersion()
    data = &Page{
      Ver: version,
      Ves: strings.ReplaceAll(version, ".", ""),
    }

    lang := initloc(r)
    data.Lan = lang

    i18n, err := goliblocale.GetLocale(cnf.Webpath + "/locale/" + lang)
    if err != nil {
      fmt.Printf("liblocaleエラー:%v", err)
      return
    }
    data.i18n = i18n
    ftmpl[0] = cnf.Webpath + "/view/index.html"
    tmpl := template.Must(template.ParseFiles(ftmpl[0], ftmpl[1], ftmpl[2]))

    if r.Method == "POST" {
      handlePost(w, r, cnf)
    }

    tmpl = template.Must(template.ParseFiles(ftmpl[0], ftmpl[1], ftmpl[2]))
    tmpl.Execute(w, data)
  }
}

// /api TODO
func apiHandler (cnf Config) func (http.ResponseWriter, *http.Request) {
  return func (w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json; charset=UTF-8")
    w.WriteHeader(200)
    version := common.GetVersion()

    buf, _ := json.MarshalIndent(
      &Stat{Url: cnf.Domain, Ver: version},
      "",
      "  ",
    )
    _, _ = w.Write(buf)
  }
}

// /archive
func archiveHandler (cnf Config) func (http.ResponseWriter, *http.Request) {
  return func (w http.ResponseWriter, r *http.Request) {
    version := common.GetVersion()

    ftmpl := []string{
      cnf.Webpath + "/view/index.html",
      cnf.Webpath + "/view/header.html",
      cnf.Webpath + "/view/footer.html",
    }

    data := &Page{Ver: version, Ves: strings.ReplaceAll(version, ".", "")}
    lang := initloc(r)
    data.Lan = lang

    i18n, err := goliblocale.GetLocale(cnf.Webpath + "/locale/" + lang)
    if err != nil {
      fmt.Printf("liblocaleエラー:%v", err)
      return
    }
    data.i18n = i18n
    ftmpl[0] = cnf.Webpath + "/view/index.html"
    tmpl := template.Must(template.ParseFiles(ftmpl[0], ftmpl[1], ftmpl[2]))
    path := strings.TrimPrefix(r.URL.Path, "/archive/")

    if strings.Contains(path, "/static/") {
      handleStatic(path, cnf, w, r)
      return
    }

    pth := r.URL.Path
    if !strings.HasSuffix(pth, "/") &&
       !strings.HasSuffix(pth, "index.html") {
      pth += "/index.html"
    } else if strings.HasSuffix(pth, "/") &&
              !strings.HasSuffix(pth, "index.html") {
      pth += "index.html"
    }

    file := cnf.Datapath + pth
    if _, err := os.Stat(file); os.IsNotExist(err) {
      http.Redirect(w, r, "/404", http.StatusSeeOther)
      return
    }

    bdy, err := os.ReadFile(file)
    if err != nil {
      http.Redirect(w, r, "/404", http.StatusSeeOther)
      return
    }

    data.Body = string(bdy)
    tmpl = template.Must(
      template.ParseFiles(cnf.Webpath + "/view/archive.html"),
    )
    tmpl.Execute(w, data)
    data = nil
  }
}

// サーバー
func Serv (cnf Config, port int) {
  http.Handle(
    "/static/",
    http.StripPrefix("/static/",
    http.FileServer(http.Dir(cnf.Webpath + "/static"))),
  )

  http.HandleFunc("/api/", apiHandler(cnf))
  http.HandleFunc("/archive/", archiveHandler(cnf))
  http.HandleFunc("/", siteHandler(cnf))

  fmt.Println(fmt.Sprint(
    "http://" + cnf.IP + ":",
    port,
    " でサーバーを実行中。終了するには、CTRL+Cを押して下さい。"),
  )
  http.ListenAndServe(fmt.Sprint(cnf.IP + ":", port), nil)
}