"""
Deep behavioral tests for content formatting patterns.
Tests markdown conversion, HTML sanitization, date formatting,
and number formatting logic.
"""

from datetime import datetime, timezone, timedelta
import re


# --- Markdown formatting patterns ---


class TestMarkdownFormatting:
    """Tests for markdown formatting patterns."""

    def _bold(self, text):
        """Make text bold in markdown."""
        return f"**{text}**"

    def _italic(self, text):
        """Make text italic in markdown."""
        return f"*{text}*"

    def _code(self, text):
        """Make text code in markdown."""
        return f"`{text}`"

    def _link(self, text, url):
        """Create markdown link."""
        return f"[{text}]({url})"

    def _heading(self, text, level=1):
        """Create markdown heading."""
        return f"{'#' * level} {text}"

    def test_bold(self):
        result = self._bold("hello")
        assert result == "**hello**"

    def test_italic(self):
        result = self._italic("hello")
        assert result == "*hello*"

    def test_code(self):
        result = self._code("print()")
        assert result == "`print()`"

    def test_link(self):
        result = self._link("Click here", "https://example.com")
        assert result == "[Click here](https://example.com)"

    def test_heading_h1(self):
        result = self._heading("Title", 1)
        assert result == "# Title"

    def test_heading_h3(self):
        result = self._heading("Section", 3)
        assert result == "### Section"


class TestMarkdownLists:
    """Tests for markdown list formatting."""

    def _bullet_list(self, items):
        """Create bullet list."""
        return "\n".join(f"- {item}" for item in items)

    def _numbered_list(self, items):
        """Create numbered list."""
        return "\n".join(f"{i + 1}. {item}" for i, item in enumerate(items))

    def _checkbox_list(self, items, checked=None):
        """Create checkbox list."""
        checked = checked or []
        lines = []
        for i, item in enumerate(items):
            box = "[x]" if i in checked else "[ ]"
            lines.append(f"- {box} {item}")
        return "\n".join(lines)

    def test_bullet_list(self):
        result = self._bullet_list(["one", "two", "three"])
        assert "- one" in result
        assert "- two" in result

    def test_numbered_list(self):
        result = self._numbered_list(["first", "second"])
        assert "1. first" in result
        assert "2. second" in result

    def test_checkbox_unchecked(self):
        result = self._checkbox_list(["task"])
        assert "[ ] task" in result

    def test_checkbox_checked(self):
        result = self._checkbox_list(["task"], checked=[0])
        assert "[x] task" in result


# --- HTML sanitization patterns ---


class TestHTMLSanitization:
    """Tests for HTML sanitization patterns."""

    def _strip_tags(self, html):
        """Remove all HTML tags."""
        return re.sub(r"<[^>]+>", "", html)

    def _escape_html(self, text):
        """Escape HTML special characters."""
        escapes = {
            "&": "&amp;",
            "<": "&lt;",
            ">": "&gt;",
            '"': "&quot;",
            "'": "&#39;",
        }
        for char, escape in escapes.items():
            text = text.replace(char, escape)
        return text

    def _sanitize_html(self, html, allowed_tags=None):
        """Sanitize HTML keeping only allowed tags."""
        allowed_tags = allowed_tags or ["p", "b", "i", "a", "br"]
        # Remove script tags completely
        html = re.sub(r"<script[^>]*>.*?</script>", "", html, flags=re.DOTALL)
        # Remove style tags completely
        html = re.sub(r"<style[^>]*>.*?</style>", "", html, flags=re.DOTALL)
        return html

    def test_strip_all_tags(self):
        result = self._strip_tags("<p>Hello <b>World</b></p>")
        assert result == "Hello World"

    def test_escape_special_chars(self):
        result = self._escape_html("<script>alert('xss')</script>")
        assert "<" not in result
        assert "&lt;" in result

    def test_sanitize_removes_script(self):
        result = self._sanitize_html("<p>Safe</p><script>evil()</script>")
        assert "<script>" not in result
        assert "Safe" in result


# --- Date formatting patterns ---


class TestDateFormatting:
    """Tests for date formatting patterns."""

    def _format_date(self, dt, format_str="%Y-%m-%d"):
        """Format date to string."""
        if not dt:
            return ""
        return dt.strftime(format_str)

    def _format_datetime(self, dt, format_str="%Y-%m-%d %H:%M:%S"):
        """Format datetime to string."""
        if not dt:
            return ""
        return dt.strftime(format_str)

    def _format_iso(self, dt):
        """Format datetime to ISO 8601."""
        if not dt:
            return ""
        return dt.isoformat()

    def test_format_date(self):
        dt = datetime(2025, 6, 15, tzinfo=timezone.utc)
        result = self._format_date(dt)
        assert result == "2025-06-15"

    def test_format_datetime(self):
        dt = datetime(2025, 6, 15, 14, 30, 0, tzinfo=timezone.utc)
        result = self._format_datetime(dt)
        assert "2025-06-15" in result
        assert "14:30:00" in result

    def test_format_iso(self):
        dt = datetime(2025, 6, 15, 14, 30, 0, tzinfo=timezone.utc)
        result = self._format_iso(dt)
        assert "2025-06-15" in result
        assert "T" in result


class TestRelativeDateFormatting:
    """Tests for relative date formatting patterns."""

    def _format_relative(self, dt):
        """Format datetime as relative time."""
        if not dt:
            return "unknown"
        now = datetime.now(timezone.utc)
        diff = now - dt
        seconds = diff.total_seconds()
        if seconds < 0:
            return "in the future"
        if seconds < 60:
            return "just now"
        minutes = seconds / 60
        if minutes < 60:
            return f"{int(minutes)} minute{'s' if minutes >= 2 else ''} ago"
        hours = minutes / 60
        if hours < 24:
            return f"{int(hours)} hour{'s' if hours >= 2 else ''} ago"
        days = hours / 24
        if days < 30:
            return f"{int(days)} day{'s' if days >= 2 else ''} ago"
        months = days / 30
        if months < 12:
            return f"{int(months)} month{'s' if months >= 2 else ''} ago"
        years = days / 365
        return f"{int(years)} year{'s' if years >= 2 else ''} ago"

    def test_just_now(self):
        dt = datetime.now(timezone.utc) - timedelta(seconds=30)
        result = self._format_relative(dt)
        assert result == "just now"

    def test_minutes_ago(self):
        dt = datetime.now(timezone.utc) - timedelta(minutes=5)
        result = self._format_relative(dt)
        assert "5 minutes ago" in result

    def test_hours_ago(self):
        dt = datetime.now(timezone.utc) - timedelta(hours=3)
        result = self._format_relative(dt)
        assert "3 hours ago" in result

    def test_days_ago(self):
        dt = datetime.now(timezone.utc) - timedelta(days=2)
        result = self._format_relative(dt)
        assert "2 days ago" in result


# --- Number formatting patterns ---


class TestNumberFormatting:
    """Tests for number formatting patterns."""

    def _format_number(self, num, decimals=0):
        """Format number with thousands separator."""
        if decimals > 0:
            return f"{num:,.{decimals}f}"
        return f"{num:,}"

    def _format_percentage(self, num, decimals=1):
        """Format number as percentage."""
        return f"{num:.{decimals}f}%"

    def _format_currency(self, num, symbol="$", decimals=2):
        """Format number as currency."""
        return f"{symbol}{num:,.{decimals}f}"

    def test_format_thousands(self):
        result = self._format_number(1234567)
        assert result == "1,234,567"

    def test_format_with_decimals(self):
        result = self._format_number(1234.5678, decimals=2)
        assert result == "1,234.57"

    def test_format_percentage(self):
        result = self._format_percentage(75.5)
        assert result == "75.5%"

    def test_format_currency(self):
        result = self._format_currency(1234.56)
        assert result == "$1,234.56"


class TestCompactNumberFormatting:
    """Tests for compact number formatting patterns."""

    def _format_compact(self, num):
        """Format large numbers compactly."""
        if num >= 1_000_000_000:
            return f"{num / 1_000_000_000:.1f}B"
        if num >= 1_000_000:
            return f"{num / 1_000_000:.1f}M"
        if num >= 1_000:
            return f"{num / 1_000:.1f}K"
        return str(num)

    def _format_bytes(self, size):
        """Format bytes to human readable."""
        for unit in ["B", "KB", "MB", "GB", "TB"]:
            if size < 1024:
                return f"{size:.1f} {unit}"
            size /= 1024
        return f"{size:.1f} PB"

    def test_format_thousands(self):
        result = self._format_compact(1500)
        assert result == "1.5K"

    def test_format_millions(self):
        result = self._format_compact(2500000)
        assert result == "2.5M"

    def test_format_billions(self):
        result = self._format_compact(3000000000)
        assert result == "3.0B"

    def test_format_bytes_kb(self):
        result = self._format_bytes(2048)
        assert "KB" in result

    def test_format_bytes_mb(self):
        result = self._format_bytes(5 * 1024 * 1024)
        assert "MB" in result


# --- Text case formatting patterns ---


class TestTextCaseFormatting:
    """Tests for text case formatting patterns."""

    def _to_title_case(self, text):
        """Convert to title case."""
        return text.title()

    def _to_sentence_case(self, text):
        """Convert to sentence case."""
        if not text:
            return ""
        return text[0].upper() + text[1:].lower()

    def _to_snake_case(self, text):
        """Convert to snake_case."""
        # Insert underscore before uppercase letters
        result = re.sub(r"([A-Z])", r"_\1", text)
        # Replace spaces and hyphens with underscores
        result = re.sub(r"[\s-]+", "_", result)
        # Collapse multiple underscores
        result = re.sub(r"_+", "_", result)
        # Remove leading underscore and lowercase
        return result.strip("_").lower()

    def _to_camel_case(self, text):
        """Convert to camelCase."""
        words = re.split(r"[\s_-]+", text)
        if not words:
            return ""
        return words[0].lower() + "".join(w.title() for w in words[1:])

    def _to_kebab_case(self, text):
        """Convert to kebab-case."""
        result = re.sub(r"([A-Z])", r"-\1", text)
        result = re.sub(r"[\s_]+", "-", result)
        # Collapse multiple hyphens
        result = re.sub(r"-+", "-", result)
        return result.strip("-").lower()

    def test_title_case(self):
        result = self._to_title_case("hello world")
        assert result == "Hello World"

    def test_sentence_case(self):
        result = self._to_sentence_case("HELLO WORLD")
        assert result == "Hello world"

    def test_snake_case(self):
        result = self._to_snake_case("Hello World")
        assert result == "hello_world"

    def test_camel_case(self):
        result = self._to_camel_case("hello world")
        assert result == "helloWorld"

    def test_kebab_case(self):
        result = self._to_kebab_case("Hello World")
        assert result == "hello-world"


# --- URL formatting patterns ---


class TestURLFormatting:
    """Tests for URL formatting patterns."""

    def _format_url(self, base, path="", params=None):
        """Format URL with path and params."""
        url = base.rstrip("/")
        if path:
            url += "/" + path.lstrip("/")
        if params:
            query = "&".join(f"{k}={v}" for k, v in params.items())
            url += "?" + query
        return url

    def _slugify(self, text):
        """Convert text to URL-safe slug."""
        # Lowercase and replace spaces with hyphens
        slug = text.lower().replace(" ", "-")
        # Remove non-alphanumeric characters except hyphens
        slug = re.sub(r"[^a-z0-9-]", "", slug)
        # Remove multiple consecutive hyphens
        slug = re.sub(r"-+", "-", slug)
        return slug.strip("-")

    def _extract_domain(self, url):
        """Extract domain from URL."""
        match = re.match(r"https?://([^/]+)", url)
        return match.group(1) if match else None

    def test_format_simple_url(self):
        result = self._format_url("https://example.com")
        assert result == "https://example.com"

    def test_format_url_with_path(self):
        result = self._format_url("https://example.com", "api/users")
        assert result == "https://example.com/api/users"

    def test_format_url_with_params(self):
        result = self._format_url("https://example.com", "", {"page": 1})
        assert "?page=1" in result

    def test_slugify(self):
        result = self._slugify("Hello World! This is a Test")
        assert result == "hello-world-this-is-a-test"

    def test_extract_domain(self):
        result = self._extract_domain("https://example.com/path")
        assert result == "example.com"


# --- JSON formatting patterns ---


class TestJSONFormatting:
    """Tests for JSON formatting patterns."""

    def _format_json_value(self, value):
        """Format value for JSON output."""
        if value is None:
            return "null"
        if isinstance(value, bool):
            return "true" if value else "false"
        if isinstance(value, str):
            return f'"{value}"'
        if isinstance(value, (int, float)):
            return str(value)
        if isinstance(value, list):
            items = ", ".join(self._format_json_value(v) for v in value)
            return f"[{items}]"
        if isinstance(value, dict):
            pairs = ", ".join(
                f'"{k}": {self._format_json_value(v)}' for k, v in value.items()
            )
            return "{" + pairs + "}"
        return str(value)

    def test_format_string(self):
        result = self._format_json_value("hello")
        assert result == '"hello"'

    def test_format_number(self):
        result = self._format_json_value(42)
        assert result == "42"

    def test_format_bool(self):
        assert self._format_json_value(True) == "true"
        assert self._format_json_value(False) == "false"

    def test_format_null(self):
        result = self._format_json_value(None)
        assert result == "null"

    def test_format_list(self):
        result = self._format_json_value([1, 2, 3])
        assert result == "[1, 2, 3]"


# --- Table formatting patterns ---


class TestTableFormatting:
    """Tests for table formatting patterns."""

    def _format_table(self, headers, rows, separator="|"):
        """Format data as ASCII table."""
        # Calculate column widths
        widths = [len(h) for h in headers]
        for row in rows:
            for i, cell in enumerate(row):
                widths[i] = max(widths[i], len(str(cell)))
        # Format header
        header_line = separator.join(
            str(h).ljust(widths[i]) for i, h in enumerate(headers)
        )
        separator_line = separator.join("-" * w for w in widths)
        # Format rows
        row_lines = []
        for row in rows:
            line = separator.join(
                str(cell).ljust(widths[i]) for i, cell in enumerate(row)
            )
            row_lines.append(line)
        return "\n".join([header_line, separator_line] + row_lines)

    def _format_csv_row(self, values, delimiter=","):
        """Format values as CSV row."""
        formatted = []
        for v in values:
            s = str(v)
            if delimiter in s or '"' in s or "\n" in s:
                s = '"' + s.replace('"', '""') + '"'
            formatted.append(s)
        return delimiter.join(formatted)

    def test_format_simple_table(self):
        headers = ["Name", "Age"]
        rows = [["Alice", 30], ["Bob", 25]]
        result = self._format_table(headers, rows)
        assert "Name" in result
        assert "Alice" in result

    def test_csv_simple(self):
        result = self._format_csv_row(["a", "b", "c"])
        assert result == "a,b,c"

    def test_csv_with_comma(self):
        result = self._format_csv_row(["hello, world", "test"])
        assert '"hello, world"' in result


# --- Pluralization patterns ---


class TestPluralization:
    """Tests for pluralization patterns."""

    def _pluralize(self, word, count):
        """Simple pluralization."""
        if count == 1:
            return word
        # Handle common irregular plurals
        irregulars = {
            "child": "children",
            "person": "people",
            "mouse": "mice",
        }
        if word in irregulars:
            return irregulars[word]
        # Handle common suffixes
        if word.endswith("y"):
            return word[:-1] + "ies"
        if word.endswith(("s", "sh", "ch", "x", "z")):
            return word + "es"
        return word + "s"

    def _format_count(self, count, singular, plural=None):
        """Format count with proper noun."""
        plural = plural or self._pluralize(singular, 2)
        noun = singular if count == 1 else plural
        return f"{count} {noun}"

    def test_regular_plural(self):
        result = self._pluralize("cat", 2)
        assert result == "cats"

    def test_singular(self):
        result = self._pluralize("cat", 1)
        assert result == "cat"

    def test_y_ending(self):
        result = self._pluralize("category", 2)
        assert result == "categories"

    def test_irregular(self):
        result = self._pluralize("child", 2)
        assert result == "children"

    def test_format_count(self):
        result = self._format_count(5, "item")
        assert result == "5 items"

    def test_format_count_singular(self):
        result = self._format_count(1, "item")
        assert result == "1 item"
