# SPDX-FileCopyrightText: 2022 Chris Heywood
#
# SPDX-License-Identifier: GPL-3.0-or-later

import os
import unittest
import warnings

from gi.repository import Gtk, GtkSource, GLib

from iotas import text_utils

warnings.filterwarnings("ignore", "version")


class Test(unittest.TestCase):

    def test_sanitise_path(self) -> None:
        self.assertEqual(text_utils.sanitise_path('..*|/\\:"<>?'), "")
        self.assertEqual(text_utils.sanitise_path(""), "")

    def test_parse_any_url_at_iter(self) -> None:
        buffer = Gtk.TextBuffer()
        start_iter = buffer.get_start_iter()
        self.assertIsNone(text_utils.parse_any_url_at_iter(start_iter, http_only=True))

        buffer = Gtk.TextBuffer()
        start_iter = buffer.get_start_iter()
        buffer.insert(start_iter, "plain")
        start_iter = buffer.get_start_iter()
        self.assertIsNone(text_utils.parse_any_url_at_iter(start_iter, http_only=True))

        buffer = Gtk.TextBuffer()
        start_iter = buffer.get_start_iter()
        buffer.insert(start_iter, "https://test.com")
        start_iter = buffer.get_start_iter()
        self.assertIsNotNone(text_utils.parse_any_url_at_iter(start_iter, http_only=True))

        buffer = Gtk.TextBuffer()
        start_iter = buffer.get_start_iter()
        buffer.insert(start_iter, "other://test.com")
        start_iter = buffer.get_start_iter()
        self.assertIsNone(text_utils.parse_any_url_at_iter(start_iter, http_only=True))

        buffer = Gtk.TextBuffer()
        start_iter = buffer.get_start_iter()
        buffer.insert(start_iter, "other://test.com")
        start_iter = buffer.get_start_iter()
        self.assertIsNotNone(text_utils.parse_any_url_at_iter(start_iter, http_only=False))

    def test_has_unicode(self) -> None:
        self.assertTrue(text_utils.has_unicode("👋"))
        self.assertFalse(text_utils.has_unicode("plain"))
        self.assertFalse(text_utils.has_unicode(""))

    def test_str_is_url(self) -> None:
        self.assertTrue(text_utils.str_is_url("https://test.com", http_only=True))
        self.assertFalse(text_utils.str_is_url("httpsX://test.com", http_only=True))
        self.assertFalse(text_utils.str_is_url("https:test.com", http_only=True))
        self.assertFalse(text_utils.str_is_url("http:test.com", http_only=True))
        self.assertFalse(text_utils.str_is_url("httptest.com", http_only=True))
        self.assertTrue(text_utils.str_is_url("other://test.com", http_only=False))
        self.assertFalse(text_utils.str_is_url("plain", http_only=False))
        self.assertFalse(text_utils.str_is_url("plain", http_only=True))
        self.assertFalse(text_utils.str_is_url("", http_only=True))
        self.assertFalse(text_utils.str_is_url("", http_only=False))

    def test_iter_forward_to_context_class_removed(self) -> None:
        manager = GtkSource.LanguageManager.get_default()
        language = manager.get_language("c")

        buffer = GtkSource.Buffer.new_with_language(language)
        start_iter = buffer.get_start_iter()
        self.__insert_into_buffer_and_wait(buffer, start_iter, "// comment\nint i = 0;")
        start_iter = buffer.get_start_iter()
        start_iter.forward_chars(5)
        self.assertEqual(buffer.get_context_classes_at_iter(start_iter), ["comment"])
        moved = text_utils.iter_forward_to_context_class_removed(start_iter, "comment")
        self.assertTrue(moved)
        self.assertEqual(start_iter.get_offset(), 10)

    def test_iter_backward_to_context_class_start(self) -> None:
        manager = GtkSource.LanguageManager.get_default()
        language = manager.get_language("c")

        buffer = GtkSource.Buffer.new_with_language(language)
        start_iter = buffer.get_start_iter()
        self.__insert_into_buffer_and_wait(buffer, start_iter, "int i = 0;\n// comment")
        end_iter = buffer.get_end_iter()
        end_iter.backward_char()
        self.assertEqual(buffer.get_context_classes_at_iter(end_iter), ["comment"])
        moved = text_utils.iter_backward_to_context_class_start(end_iter, "comment")
        self.assertTrue(moved)
        self.assertEqual(end_iter.get_offset(), 11)

    def test_get_iters_at_sourceview_context_class_extents(self) -> None:
        manager = GtkSource.LanguageManager.get_default()
        language = manager.get_language("c")

        buffer = GtkSource.Buffer.new_with_language(language)
        start_iter = buffer.get_start_iter()
        self.__insert_into_buffer_and_wait(buffer, start_iter, "int i = 0;\n// comment\nint j = 0;")
        inside_iter = buffer.get_start_iter()
        inside_iter.forward_chars(11)
        self.assertEqual(buffer.get_context_classes_at_iter(inside_iter), ["comment"])
        start, end = text_utils.get_iters_at_sourceview_context_class_extents(
            "comment", inside_iter
        )
        self.assertIsNotNone(start)
        assert start is not None  # mypy
        self.assertIsNotNone(end)
        assert end is not None  # mypy
        self.assertEqual(start.get_offset(), 11)
        self.assertEqual(end.get_offset(), 21)

    def test_parse_markdown_inline_link(self) -> None:
        _manager, language = self.__get_language()

        buffer = GtkSource.Buffer.new_with_language(language)
        start_iter = buffer.get_start_iter()
        self.__insert_into_buffer_and_wait(buffer, start_iter, "plain")
        inside_iter = buffer.get_start_iter()
        inside_iter.forward_chars(3)
        self.assertIsNone(text_utils.parse_markdown_inline_link(inside_iter))

        buffer = GtkSource.Buffer.new_with_language(language)
        start_iter = buffer.get_start_iter()
        self.__insert_into_buffer_and_wait(buffer, start_iter, "[text](https://linky.com)")
        inside_iter = buffer.get_start_iter()
        inside_iter.forward_chars(3)
        details = text_utils.parse_markdown_inline_link(inside_iter)
        self.assertIsNotNone(details)
        assert details is not None  # mypy
        self.assertEqual(details.link, "https://linky.com")
        self.assertEqual(details.text, "text")
        self.assertEqual(details.title, "")
        self.assertFalse(details.url_angle_bracketed)
        self.assertEqual(details.source_text, "[text](https://linky.com)")
        self.assertEqual(details.start_offset, 0)
        self.assertEqual(details.end_offset, 25)

        buffer = GtkSource.Buffer.new_with_language(language)
        start_iter = buffer.get_start_iter()
        self.__insert_into_buffer_and_wait(buffer, start_iter, '[text](https://linky.com "title")')
        inside_iter = buffer.get_start_iter()
        inside_iter.forward_chars(3)
        details = text_utils.parse_markdown_inline_link(inside_iter)
        self.assertIsNotNone(details)
        assert details is not None  # mypy
        self.assertEqual(details.link, "https://linky.com")
        self.assertEqual(details.text, "text")
        self.assertEqual(details.title, "title")
        self.assertFalse(details.url_angle_bracketed)
        self.assertEqual(details.source_text, '[text](https://linky.com "title")')
        self.assertEqual(details.start_offset, 0)
        self.assertEqual(details.end_offset, 33)

        buffer = GtkSource.Buffer.new_with_language(language)
        start_iter = buffer.get_start_iter()
        self.__insert_into_buffer_and_wait(buffer, start_iter, "[text](<https://linky.com>)")
        inside_iter = buffer.get_start_iter()
        inside_iter.forward_chars(3)
        details = text_utils.parse_markdown_inline_link(inside_iter)
        self.assertIsNotNone(details)
        assert details is not None  # mypy
        self.assertEqual(details.link, "https://linky.com")
        self.assertEqual(details.text, "text")
        self.assertEqual(details.title, "")
        self.assertTrue(details.url_angle_bracketed)
        self.assertEqual(details.source_text, "[text](<https://linky.com>)")
        self.assertEqual(details.start_offset, 0)
        self.assertEqual(details.end_offset, 27)

    def test_parse_markdown_automatic_link(self) -> None:
        _manager, language = self.__get_language()

        buffer = GtkSource.Buffer.new_with_language(language)
        start_iter = buffer.get_start_iter()
        self.__insert_into_buffer_and_wait(buffer, start_iter, "plain")
        inside_iter = buffer.get_start_iter()
        inside_iter.forward_chars(3)
        self.assertIsNone(text_utils.parse_markdown_automatic_link(inside_iter))

        buffer = GtkSource.Buffer.new_with_language(language)
        start_iter = buffer.get_start_iter()
        self.__insert_into_buffer_and_wait(buffer, start_iter, " <https://linky.com> ")
        inside_iter = buffer.get_start_iter()
        inside_iter.forward_chars(3)
        details = text_utils.parse_markdown_automatic_link(inside_iter)
        self.assertIsNotNone(details)
        assert details is not None  # mypy
        self.assertEqual(details.link, "https://linky.com")
        self.assertEqual(details.source_text, "<https://linky.com>")
        self.assertEqual(details.start_offset, 1)
        self.assertEqual(details.end_offset, 20)

        buffer = GtkSource.Buffer.new_with_language(language)
        start_iter = buffer.get_start_iter()
        self.__insert_into_buffer_and_wait(buffer, start_iter, "[text](<https://linky.com>)")
        inside_iter = buffer.get_start_iter()
        inside_iter.forward_chars(9)
        self.assertIsNone(text_utils.parse_markdown_automatic_link(inside_iter))

    def __insert_into_buffer_and_wait(
        self, buffer: GtkSource.Buffer, location: Gtk.TextIter, text: str
    ) -> None:
        context = GLib.MainContext.default()
        buffer.connect("highlight-updated", self.__flag_not_waiting)
        self.awaiting_signal = True
        buffer.insert(location, text)
        while self.awaiting_signal:
            context.iteration(False)

    def __flag_not_waiting(self, *_args) -> None:
        self.awaiting_signal = False

    def __get_language(self) -> tuple[GtkSource.LanguageManager, GtkSource.Language]:
        manager = GtkSource.LanguageManager()
        file_dir = os.path.dirname(__file__)
        language_path = os.path.join(
            file_dir, os.pardir, "data", "gtksourceview-5", "language-specs"
        )
        manager.prepend_search_path(language_path)
        language = manager.get_language("iotas-markdown")
        return (manager, language)
