package onnx

import (
	"strings"
	"unicode"
)

// H2Z converts half-width (hankaku) ascii, digits, and katakana to
// full-width (zenkaku), matching Python jaconv.h2z(text, ascii=True, digit=True).
func H2Z(text string) string {
	if text == "" {
		return ""
	}

	// First convert two-character voiced kana combinations (e.g. ｶﾞ -> ガ, ﾊﾟ -> パ).
	text = convertVoicedKana(text)

	var b strings.Builder
	b.Grow(len(text) * 2)

	for _, r := range text {
		if r == ' ' {
			b.WriteRune('\u3000') // full-width ideographic space
			continue
		}
		// ASCII printable: '!' (0x21) to '~' (0x7E)
		if r >= 0x21 && r <= 0x7E {
			b.WriteRune(r + 0xFEE0)
			continue
		}
		// Single half-width kana mapping (0xFF61 to 0xFF9F)
		if z, ok := singleKanaMap[r]; ok {
			b.WriteRune(z)
			continue
		}
		b.WriteRune(r)
	}
	return b.String()
}

func convertVoicedKana(s string) string {
	// Replace 2-char voiced / semi-voiced kana
	for oldR, newR := range voicedKanaMap {
		s = strings.ReplaceAll(s, oldR, newR)
	}
	return s
}

var voicedKanaMap = map[string]string{
	"ｶﾞ": "ガ", "ｷﾞ": "ギ", "ｸﾞ": "グ", "ｹﾞ": "ゲ", "ｺﾞ": "ゴ",
	"ｻﾞ": "ザ", "ｼﾞ": "ジ", "ｽﾞ": "ズ", "ｾﾞ": "ゼ", "ｿﾞ": "ゾ",
	"ﾀﾞ": "ダ", "ﾁﾞ": "ヂ", "ﾂﾞ": "ヅ", "ﾃﾞ": "デ", "ﾄﾞ": "ド",
	"ﾊﾞ": "バ", "ﾋﾞ": "ビ", "ﾌﾞ": "ブ", "ﾍﾞ": "ベ", "ﾎﾞ": "ボ",
	"ﾊﾟ": "パ", "ﾋﾟ": "ピ", "ﾌﾟ": "プ", "ﾍﾟ": "ペ", "ﾎﾟ": "ポ",
	"ｳﾞ": "ヴ",
}

var singleKanaMap = map[rune]rune{
	'｡': '。', '｢': '「', '｣': '」', '､': '、', '･': '・',
	'ｦ': 'ヲ', 'ｧ': 'ァ', 'ｨ': 'ィ', 'ｩ': 'ゥ', 'ｪ': 'ェ',
	'ｫ': 'ォ', 'ｬ': 'ャ', 'ｭ': 'ュ', 'ｮ': 'ョ', 'ｯ': 'ッ',
	'ｰ': 'ー', 'ｱ': 'ア', 'ｲ': 'イ', 'ｳ': 'ウ', 'ｴ': 'エ',
	'ｵ': 'オ', 'ｶ': 'カ', 'ｷ': 'キ', 'ｸ': 'ク', 'ｹ': 'ケ',
	'ｺ': 'コ', 'ｻ': 'サ', 'ｼ': 'シ', 'ｽ': 'ス', 'ｾ': 'セ',
	'ｿ': 'ソ', 'ﾀ': 'タ', 'ﾁ': 'チ', 'ﾂ': 'ツ', 'ﾃ': 'テ',
	'ﾄ': 'ト', 'ﾅ': 'ナ', 'ﾆ': 'ニ', 'ﾇ': 'ヌ', 'ﾈ': 'ネ',
	'ﾉ': 'ノ', 'ﾊ': 'ハ', 'ﾋ': 'ヒ', 'ﾌ': 'フ', 'ﾍ': 'ヘ',
	'ﾎ': 'ホ', 'ﾏ': 'マ', 'ﾐ': 'ミ', 'ﾑ': 'ム', 'ﾒ': 'メ',
	'ﾓ': 'モ', 'ﾔ': 'ヤ', 'ﾕ': 'ユ', 'ﾖ': 'ヨ', 'ﾗ': 'ラ',
	'ﾘ': 'リ', 'ﾙ': 'ル', 'ﾚ': 'レ', 'ﾛ': 'ロ', 'ﾜ': 'ワ',
	'ﾝ': 'ン', // jaconv leaves a lone ﾞ or ﾟ half-width
}

// IsKanaOnly returns true if every non-space, non-punctuation rune is Hiragana or Katakana.
func IsKanaOnly(s string) bool {
	trimmed := strings.TrimSpace(s)
	if trimmed == "" {
		return true
	}
	hasKana := false
	for _, r := range trimmed {
		if unicode.IsPunct(r) || unicode.IsSpace(r) {
			continue
		}
		if (r >= 0x3040 && r <= 0x309F) || // Hiragana
			(r >= 0x30A0 && r <= 0x30FF) || // Katakana
			(r >= 0x31F0 && r <= 0x31FF) || // Small Katakana extensions
			r == 0x30FC || // Prolonged sound mark ー
			(r >= 0xFF66 && r <= 0xFF9F) { // Half-width kana
			hasKana = true
			continue
		}
		return false
	}
	return hasKana
}
