package elinps

import (
	"bytes"
	"fmt"
	"html/template"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/yuin/goldmark"
)

// ReadmePage serve o README.md renderizado como HTML.
//
// Motivação: dar uma "home" simples para o serviço (documentação em tempo real).
// Sem autenticação, conforme solicitado.
//
// Implementação: cache em memória por mtime para evitar renderização em toda request.
type ReadmePage struct {
	caminho string

	mu          sync.Mutex
	ultimoMTime time.Time
	html        []byte
	errMsg      string
}

func NewReadmePage(caminho string) *ReadmePage {
	return &ReadmePage{caminho: caminho}
}

func (p *ReadmePage) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Só respondemos GET/HEAD.
	if r.Method != http.MethodGet && r.Method != http.MethodHead {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}

	html, errMsg := p.renderIfNeeded()
	if errMsg != "" {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte(errMsg))
		return
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.WriteHeader(http.StatusOK)
	if r.Method == http.MethodHead {
		return
	}
	w.Write(html)
}

func (p *ReadmePage) renderIfNeeded() ([]byte, string) {
	p.mu.Lock()
	defer p.mu.Unlock()

	st, err := os.Stat(p.caminho)
	if err != nil {
		p.errMsg = fmt.Sprintf("README não encontrado: %s", p.caminho)
		p.html = nil
		p.ultimoMTime = time.Time{}
		return nil, p.errMsg
	}

	// Cache: se o arquivo não mudou, devolve o HTML já renderizado.
	if p.html != nil && st.ModTime().Equal(p.ultimoMTime) {
		return p.html, ""
	}

	md, err := os.ReadFile(p.caminho)
	if err != nil {
		p.errMsg = "erro ao ler README"
		p.html = nil
		p.ultimoMTime = time.Time{}
		return nil, p.errMsg
	}

	var buf bytes.Buffer
	if err := goldmark.Convert(md, &buf); err != nil {
		p.errMsg = "erro ao renderizar README"
		p.html = nil
		p.ultimoMTime = time.Time{}
		return nil, p.errMsg
	}

	// Envelopa em uma página com estilo básico.
	// Importante: NÃO usamos fmt.Sprintf com o HTML/CSS diretamente,
	// porque o CSS pode conter "%" (ex.: width:100%) e o fmt interpreta
	// como placeholders.
	page := `<!doctype html>
<html lang="pt-br">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>e-li.nps • README</title>
  <style>
    body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;margin:0;background:#fafafa;color:#111;}
    .wrap{max-width:980px;margin:0 auto;padding:24px;}
    .card{background:#fff;border:1px solid #e5e5e5;border-radius:12px;padding:22px;}
    h1,h2,h3{margin-top:1.2em;}
    pre{background:#0b1020;color:#e6e6e6;padding:14px;border-radius:12px;overflow:auto;}
    code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace;}
    table{border-collapse:collapse;width:100%;}
    th,td{border:1px solid #e5e5e5;padding:8px;text-align:left;}
    a{color:#111;}
    .muted{color:#666;font-size:12px;}
  </style>
</head>
<body>
  <div class="wrap">
    <div class="card">
      <!--CONTEUDO_README-->
      <p class="muted" style="margin-top:16px;">Página gerada automaticamente a partir de README.md</p>
    </div>
  </div>
</body>
</html>`

	html := []byte(strings.Replace(page, "<!--CONTEUDO_README-->", buf.String(), 1))

	// Sanitização mínima: como o README é do próprio projeto, aceitamos o HTML gerado.
	// Se quiser endurecer segurança, podemos usar um sanitizer (bluemonday).
	_ = template.HTMLEscapeString

	p.html = html
	p.errMsg = ""
	p.ultimoMTime = st.ModTime()
	return p.html, ""
}
