package models_pages

import (
	"bytes"
	"fmt"
	"html/template"
	"log"
	"main/tools"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"time"
)

const (
	// Имя соответствующего шаблона
	PostsPageTmplName = "posts.gohtml"
)

type PostsMap map[PostLink]*Post
type PostsPage struct {
	PostsListOnPage []*Post // список постов на странице
	PageNumber      int     // номер страницы
	PagesCount      int     // общее количество страниц
}

func LoadPosts(dir string) (PostsMap, error) {

	posts := PostsMap{}

	err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !f.IsDir() && strings.HasSuffix(f.Name(), ".md") {

			md, err := os.ReadFile(path)
			if err != nil {
				return err
			}

			html := tools.MdToHTML(md)

			name := filepath.Base(path)
			lowLineIndex := strings.Index(name, "_")

			if lowLineIndex == -1 {
				// Обработка случая, если "_" нет в имени
				log.Fatal(`post name parse error`)
			}

			timestampStr := name[:lowLineIndex]
			timestamp, err := strconv.ParseInt(timestampStr, 10, 64)
			if err != nil {
				// Ошибка парсинга timestamp
				log.Fatal(`post name parse error`)
			}
			link := fmt.Sprintf("/%s", strings.TrimSuffix(name[lowLineIndex+1:], ".md"))
			posts[PostLink(link)] = createPost(link, html, timestamp)
		}
		return nil
	})

	if err != nil {
		return nil, err
	}

	return posts, nil
}

// Получение из мапы постов списка постов, отсортированного по ModTimestamp (новые сначала)
func (p *PostsMap) PostsList() []*Post {
	postsSlice := make([]*Post, 0, len(*p))
	for _, post := range *p {
		postsSlice = append(postsSlice, post)
	}

	sort.Slice(postsSlice, func(i, j int) bool {
		return postsSlice[i].Timestamp > postsSlice[j].Timestamp
	})

	return postsSlice
}

func CreatePage(postsList []*Post, pageNumber, postsMaxCountOnPage int) *PostsPage {
	// Общее количество страниц
	pagesCount := (len(postsList) + postsMaxCountOnPage - 1) / postsMaxCountOnPage

	// Ошибки тут быть не может, так как этот обработчик настроен
	// на только существующие реально pageNumber и в случае
	// какого то не существующего номера страницы он просто
	// не сработает (в главном main настроены маршруты)

	startIndex := pageNumber * postsMaxCountOnPage
	endIndex := startIndex + postsMaxCountOnPage
	endIndex = min(endIndex, len(postsList))
	postsSublistForPageNumber := postsList[startIndex:endIndex]

	return &PostsPage{
		PostsListOnPage: postsSublistForPageNumber,
		PageNumber:      pageNumber,
		PagesCount:      pagesCount,
	}
}

func (p *PostsPage) RenderPostsPage(templates *template.Template, version int64) ([]byte, error) {
	var pageData bytes.Buffer

	var prevPageNumber, nextPageNumber int

	if p.PageNumber == 0 {
		prevPageNumber = p.PagesCount - 1
	} else {
		prevPageNumber = p.PageNumber - 1
	}

	nextPageNumber = (p.PageNumber + 1) % p.PagesCount

	pagi := fmt.Sprintf(
		`<a href="/posts/%d"><-</a> %d/%d <a href="/posts/%d">-></a>`,
		prevPageNumber,
		p.PageNumber+1,
		p.PagesCount,
		nextPageNumber,
	)

	context := map[string]any{
		"pagi":               template.HTML(pagi),
		"version":            version,
		"renderingTimestamp": time.Now().Unix(),
		"posts":              p.PostsListOnPage,
	}

	if err := templates.ExecuteTemplate(&pageData, PostsPageTmplName, context); err != nil {
		return nil, err
	}

	return pageData.Bytes(), nil
}
