// Unicode: байты, code points и UTF-8 в Zig
// Компиляция: zig build-exe unicode_demo.zig && ./unicode_demo

const std = @import("std");

pub fn main() !void {
    const stdout = std.fs.File.stdout().deprecatedWriter();

    // 1. Байты vs code points
    const s = "Привет 🌍";
    try stdout.print("«{s}»\n", .{s});
    try stdout.print("  Байт: {d}\n", .{s.len});
    try stdout.print("  Code points: {d}\n", .{countCodePoints(s)});

    // 2. Нормализация: предсоставленная vs разложенная «й»
    const y1 = "й"; // U+0439 — одна code point (2 байта в UTF-8)
    const y2 = "и\u{0306}"; // U+0438 + U+0306 — две code points (4 байта)
    try stdout.print("\n--- Нормализация ---\n", .{});
    try stdout.print("Предсоставленная: {d} байт, {d} code point(s)\n", .{ y1.len, countCodePoints(y1) });
    try stdout.print("Разложенная:      {d} байт, {d} code point(s)\n", .{ y2.len, countCodePoints(y2) });
    try stdout.print("Побайтово равны: {}\n", .{std.mem.eql(u8, y1, y2)});

    // 3. Эмодзи-семья: один глиф — много code points
    const family = "👨\u{200D}👩\u{200D}👧\u{200D}👦";
    try stdout.print("\n--- Эмодзи ---\n", .{});
    try stdout.print("Семья: {s}\n", .{family});
    try stdout.print("  Байт: {d}\n", .{family.len});
    try stdout.print("  Code points: {d}\n", .{countCodePoints(family)});
    try stdout.print("  Состав:", .{});

    var family_view = try std.unicode.Utf8View.init(family);
    var family_iter = family_view.iterator();
    while (family_iter.nextCodepoint()) |cp| {
        try stdout.print(" U+{X:0>4}", .{cp});
    }
    try stdout.print("\n", .{});

    // 4. Байтовый доступ vs code point доступ
    const hello = "Здравствуйте";
    try stdout.print("\n--- Байтовый доступ ---\n", .{});
    try stdout.print("Байт: {d}, Code points: {d}\n", .{ hello.len, countCodePoints(hello) });
    try stdout.print("hello[0] = 0x{X:0>2} (первый байт, не буква!)\n", .{hello[0]});

    // Безопасное извлечение первой code point
    var hello_view = try std.unicode.Utf8View.init(hello);
    var hello_iter = hello_view.iterator();
    if (hello_iter.nextCodepoint()) |first_cp| {
        try stdout.print("Первая code point: U+{X:0>4}\n", .{first_cp});
    }

    // 5. Гомоглифы
    const latin_a: u21 = 'a'; // U+0061
    const cyrillic_a: u21 = '\u{0430}'; // U+0430
    try stdout.print("\n--- Гомоглифы ---\n", .{});
    try stdout.print("Латинская  'a' = U+{X:0>4}\n", .{latin_a});
    try stdout.print("Кириллическая  = U+{X:0>4}\n", .{cyrillic_a});
    try stdout.print("Равны: {}\n", .{latin_a == cyrillic_a});
}

fn countCodePoints(s: []const u8) usize {
    var view = std.unicode.Utf8View.init(s) catch return 0;
    var iter = view.iterator();
    var count: usize = 0;
    while (iter.nextCodepoint()) |_| {
        count += 1;
    }
    return count;
}
