package services

import (
	"fmt"
	"regexp"
	"strings"
)

const replyPresentationInstruction = `
FORMAT PESAN WHATSAPP:
- Pilih bentuk sesuai isi, bukan selalu paragraf panjang atau selalu daftar.
- Sapaan, satu fakta, atau satu klarifikasi: cukup paragraf pendek tanpa daftar.
- Dua atau lebih produk, pilihan harga, atau beberapa fitur/syarat sejajar: gunakan daftar dengan awalan "- " dan satu item per baris. Sertakan nama produk/paket agar harga tidak tertukar. Contoh bentuk saja: "- Paket Basic: Rp190.000" lalu baris baru "- Paket Pro: Rp200.000". Angka contoh BUKAN fakta bisnis.
- Untuk urutan tindakan gunakan "1. ", "2. ", dan seterusnya, satu langkah per baris. Jangan memakai nomor untuk pilihan yang tidak berurutan.
- Pisahkan pembuka singkat, daftar, perubahan topik, dan pertanyaan lanjutan dengan SATU baris kosong. Tidak perlu baris kosong antar item daftar pendek.
- Harga normal dan promo dari produk yang sama boleh tetap satu kalimat. Rentang harga dan persamaan subtotal juga boleh satu baris agar maknanya tidak berubah.
- Saat menyebut harga, tetap sertakan syarat harga yang relevan dari sumber, misalnya belum termasuk pajak/ongkir atau pembayaran sekali. Mode singkat tidak boleh menghilangkan syarat tersebut.
- Gunakan *tebal* hanya untuk judul/label penting jika membantu. Jangan memakai tabel Markdown, judul #, atau tanda pisah panjang Unicode (U+2014/U+2013) dalam narasi; pilih titik, koma, atau titik dua.
- Pertahankan ejaan nama produk, URL, kode, nominal, satuan, dan syarat dari sumber. Jangan menambah harga/fitur yang tidak ditanyakan hanya untuk membuat daftar. Daftar tetap mengikuti batas panjang yang dipilih pengguna.
`

var replyLiteralPattern = regexp.MustCompile("(?i)```[\\s\\S]*?(?:```|$)|`[^`\\n]+`|https?://[^\\s<>]+|\\[\\[[^\\[\\]\\r\\n]*\\]\\]")
var replyListLinePattern = regexp.MustCompile(`^[\t ]*(?:[-•]|[0-9]+[.)])[\t ]+\S`)
var inlineReplyListPattern = regexp.MustCompile(`(?:^|[\t :;])(?:[-•]|[0-9]{1,2}[.)])[\t ]+\S`)
var replyPriceRangePattern = regexp.MustCompile(`(?i)\brp\.?\s*[0-9][0-9.,]*\s*(?:-|sampai|hingga|s\.d\.?)\s*(?:rp\.?\s*)?[0-9]`)
var replyPromotionPattern = regexp.MustCompile(`(?i)\b(?:harga\s+(?:normal|awal|asli)|promo|diskon|dari\s+(?:harga\s+)?rp)\b`)
var replyCalculationPattern = regexp.MustCompile(`(?i)(?:×|\b[0-9]+\s*x\s*rp|\bsubtotal\b|\btotal\b[^\n]*=)`)
var replyStepsRequestPattern = regexp.MustCompile(`(?i)\b(?:cara(?:nya)?|langkah(?:-langkah)?|prosedur|tahapan|urutan)\b`)
var replySequencePattern = regexp.MustCompile(`(?i)\b(?:lalu|kemudian|selanjutnya|setelah itu|berikutnya)\b`)
var replyNumberedLinePattern = regexp.MustCompile(`(?m)^\s*[0-9]+[.)][\t ]+\S`)

// Formatting must never mutate an opaque link, code sample or workflow token.
// The placeholder prefix is chosen outside the input so restoration is exact.
func maskReplyLiterals(reply string) (string, func(string) string) {
	prefix := "\x00reply_literal_"
	for strings.Contains(reply, prefix) {
		prefix += "_"
	}
	pairs := []string{}
	masked := replyLiteralPattern.ReplaceAllStringFunc(reply, func(literal string) string {
		key := fmt.Sprintf("%s%d\x00", prefix, len(pairs)/2)
		pairs = append(pairs, key, literal)
		return key
	})
	return masked, func(formatted string) string {
		if len(pairs) == 0 {
			return formatted
		}
		return strings.NewReplacer(pairs...).Replace(formatted)
	}
}

// Only punctuation, bullet markers and whitespace are normalized. Choosing
// what to list stays with the model; we never split prices using a blind regex.
func normalizeCustomerReplyLayout(reply string) string {
	masked, restore := maskReplyLiterals(reply)
	masked = strings.NewReplacer("\r\n", "\n", "\r", "\n", "\u2014", "-", "\u2013", "-").Replace(masked)
	lines := strings.Split(masked, "\n")
	result := make([]string, 0, len(lines)+4)
	previousList := false
	for _, line := range lines {
		line = strings.TrimRight(line, " \t")
		trimmed := strings.TrimLeft(line, " \t")
		if strings.HasPrefix(trimmed, "• ") {
			line = strings.TrimSuffix(line, trimmed) + "- " + strings.TrimPrefix(trimmed, "• ")
		}
		if strings.TrimSpace(line) == "" {
			if len(result) > 0 && result[len(result)-1] != "" {
				result = append(result, "")
			}
			continue
		}
		isList := replyListLinePattern.MatchString(line)
		// Indented lines may continue the preceding item. Preserve that grouping.
		continuation := previousList && len(line) > len(strings.TrimLeft(line, " \t"))
		if len(result) > 0 && result[len(result)-1] != "" && isList != previousList && !continuation {
			result = append(result, "")
		}
		result = append(result, line)
		previousList = isList || continuation
	}
	return strings.TrimSpace(restore(strings.Join(result, "\n")))
}

func replyPresentationIssue(reply string, stepsRequested bool) string {
	prose, _ := maskReplyLiterals(reply)
	for _, line := range strings.Split(prose, "\n") {
		if len(inlineReplyListPattern.FindAllStringIndex(line, -1)) > 1 {
			return "list_layout_required"
		}
	}
	prices := rupiahAmountPattern.FindAllString(prose, -1)
	// A single action or clarification needs no invented steps. Recall of a
	// past conversation can also use "lalu" without becoming an instruction.
	if stepsRequested && replySequencePattern.MatchString(prose) && !isPlainClarification(reply) &&
		len(replyNumberedLinePattern.FindAllString(prose, -1)) < 2 {
		return "steps_layout_required"
	}
	// Repeating one amount to explain payment terms is still one price.
	distinctPrices := strictAnswerNumbers(strings.Join(prices, " "))
	if len(distinctPrices) >= 2 && !replyCalculationPattern.MatchString(prose) &&
		!(len(prices) == 2 && (replyPriceRangePattern.MatchString(prose) || replyPromotionPattern.MatchString(prose))) {
		priceLines := 0
		for _, line := range strings.Split(prose, "\n") {
			if replyListLinePattern.MatchString(line) && rupiahAmountPattern.MatchString(line) {
				priceLines++
			}
		}
		if priceLines < 2 {
			return "price_list_required"
		}
	}
	for _, paragraph := range strings.Split(prose, "\n\n") {
		if len([]rune(paragraph)) <= 600 {
			continue
		}
		hasList := false
		for _, line := range strings.Split(paragraph, "\n") {
			hasList = hasList || replyListLinePattern.MatchString(line)
		}
		if !hasList {
			return "paragraph_layout_required"
		}
	}
	return ""
}
