package pdf

import (
	"bytes"
	"embed"
	"evening_detective/internal/models"
	"strings"

	"github.com/signintech/gopdf"
	"github.com/skip2/go-qrcode"
)

//go:embed JetBrainsMono-Medium.ttf
var f embed.FS

type service struct{}

func NewPDFGenerator() IPDFGenerator {
	return &service{}
}

func (s *service) CreateTeamsPDF(teams []*models.Team) ([]byte, error) {
	pdf := &gopdf.GoPdf{}
	pdf.Start(gopdf.Config{PageSize: *gopdf.PageSizeA4}) // W: 595, H: 842
	file, err := f.Open("JetBrainsMono-Medium.ttf")
	if err != nil {
		return nil, err
	}
	if err := pdf.AddTTFFontByReader("main", file); err != nil {
		return nil, err
	}
	if err := pdf.SetFont("main", "", 10); err != nil {
		return nil, err
	}

	countOnPage := 9
	padding := 17.
	xDelta := 187.
	yDelta := 260.
	for i, team := range teams {
		if i%countOnPage == 0 {
			pdf.AddPage()
			pdf.SetPage(1 + i/countOnPage)
		}
		y := (padding + 15) + yDelta*float64(i%countOnPage/3)
		x := padding + xDelta*float64(i%3)

		if err := printTextCenter(pdf, "Подключите Wi-Fi", xDelta-6, x+3, y); err != nil {
			return nil, err
		}
		if err := printTextCenter(pdf, "Имя: evening_detective", xDelta-6, x+3, 15+y); err != nil {
			return nil, err
		}
		if err := printTextCenter(pdf, "Пароль: 12345678", xDelta-6, x+3, 30+y); err != nil {
			return nil, err
		}
		if err := printQR(pdf, team.Link, x+21, 65+y); err != nil {
			return nil, err
		}
		if err := printTextCenter(pdf, "Войдите в приложение по qr", xDelta-6, x+3, 55+y); err != nil {
			return nil, err
		}
		if err := printTextCenter(pdf, team.Name, xDelta-6, x+3, 55+y+150); err != nil {
			return nil, err
		}
	}
	buffer := &bytes.Buffer{}
	_, err = pdf.WriteTo(buffer)
	return buffer.Bytes(), err
}

func printQR(pdf *gopdf.GoPdf, url string, x, y float64) error {
	png, err := qrcode.Encode(url, qrcode.Medium, 256)
	if err != nil {
		return err
	}
	imgHolder, err := gopdf.ImageHolderByBytes(png)
	if err != nil {
		return err
	}
	err = pdf.ImageByHolder(imgHolder, x, y, &gopdf.Rect{W: 145, H: 145})
	if err != nil {
		return err
	}
	return nil
}

func printTextCenter(pdf *gopdf.GoPdf, text string, pageWidth, x, y float64) error {
	lines := splitTextByWords(pdf, text, pageWidth)
	for i, line := range lines {
		lineWidth, err := pdf.MeasureTextWidth(line)
		if err != nil {
			return err
		}

		xLine := x + (pageWidth-lineWidth)/2
		yLine := y + 15*float64(i)
		pdf.SetXY(xLine, yLine)

		pdf.Cell(nil, line)
	}
	return nil
}

func splitTextByWords(pdf *gopdf.GoPdf, text string, maxWidth float64) []string {
	words := strings.Fields(text)
	var lines []string
	var currentLine string

	for _, word := range words {
		testLine := currentLine
		if testLine != "" {
			testLine += " " + word
		} else {
			testLine = word
		}

		width, _ := pdf.MeasureTextWidth(testLine)

		if width <= maxWidth {
			currentLine = testLine
		} else {
			if currentLine != "" {
				lines = append(lines, currentLine)
			}
			currentLine = word
		}
	}

	if currentLine != "" {
		lines = append(lines, currentLine)
	}

	return lines
}
