/* window_content.rs
 *
 * Copyright 2026 Christian Kruse
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

use relm4::gtk;
use relm4::gtk::prelude::*;

pub fn hard_wrap_buffer(buf: &gtk::TextBuffer, max_len: usize) {
    let text = buf.text(&buf.start_iter(), &buf.end_iter(), false).to_string();

    let cursor_offset = buf.cursor_position() as usize;
    let wrapped = hard_wrap_text(&text, max_len);

    if wrapped != text {
        let new_cursor = cursor_offset.min(wrapped.chars().count());
        buf.set_text(&wrapped);

        let iter = buf.iter_at_offset(new_cursor as i32);
        buf.place_cursor(&iter);
    }
}

fn hard_wrap_text(text: &str, max_len: usize) -> String {
    // 16 is rather random, but it should be enough to avoid reallocations in most cases
    let mut result = String::with_capacity(text.len() + 16);

    for (line_idx, line) in text.split('\n').enumerate() {
        if line_idx > 0 {
            result.push('\n');
        }

        let char_count = line.chars().count();
        if char_count <= max_len {
            result.push_str(line);
            continue;
        }

        let mut remaining = line;
        let mut first = true;

        while remaining.chars().count() > max_len {
            if !first {
                result.push('\n');
            }

            first = false;

            let byte_limit = remaining
                .char_indices()
                .nth(max_len)
                .map(|(i, _)| i)
                .unwrap_or(remaining.len());

            let break_at = remaining[..byte_limit].rfind(' ');

            if let Some(pos) = break_at {
                result.push_str(&remaining[..pos]);
                remaining = &remaining[pos + 1..];
            } else {
                // No space found: hard break at max_len
                result.push_str(&remaining[..byte_limit]);
                remaining = &remaining[byte_limit..];
            }
        }

        if !first {
            result.push('\n');
        }

        result.push_str(remaining);
    }

    result
}
