"""Tests for PIM contacts data layer."""

from __future__ import annotations

from pathlib import Path

import pytest
from icarus.pim.contacts import (
    _slugify,
    create_contact,
    parse_vcard,
    search_contacts,
    update_contact,
    write_vcard,
)


class TestSlugify:
    def test_simple_name(self):
        assert _slugify("John Doe") == "john-doe"

    def test_unicode_name(self):
        assert _slugify("María José García") == "maria-jose-garcia"

    def test_empty_name(self):
        assert _slugify("") == "unnamed"

    def test_special_characters(self):
        assert _slugify("O'Brien-Smith") == "o-brien-smith"


class TestParseWriteVcard:
    def test_roundtrip(self, tmp_path: Path):
        data = {
            "fn": "Jane Doe",
            "email": ["jane@example.com"],
            "tel": ["+1234567890"],
            "org": "Acme Corp",
            "title": "CTO",
            "note": "Prefers morning meetings",
        }
        path = tmp_path / "jane-doe.vcf"
        write_vcard(path, data)

        parsed = parse_vcard(path)
        assert parsed["fn"] == "Jane Doe"
        assert "jane@example.com" in parsed["email"]
        assert "+1234567890" in parsed["tel"]
        assert parsed["org"] == "Acme Corp"
        assert parsed["title"] == "CTO"
        assert parsed["note"] == "Prefers morning meetings"

    def test_x_icarus_fields(self, tmp_path: Path):
        data = {
            "fn": "Test Person",
            "x_fields": {"X-ICARUS-PROJECT": "icarus", "X-ICARUS-TAGS": "dev,friend"},
        }
        path = tmp_path / "test.vcf"
        write_vcard(path, data)

        parsed = parse_vcard(path)
        assert parsed["x_fields"]["X-ICARUS-PROJECT"] == "icarus"
        assert parsed["x_fields"]["X-ICARUS-TAGS"] == "dev,friend"

    def test_multiple_emails(self, tmp_path: Path):
        data = {"fn": "Multi Email", "email": ["a@test.com", "b@test.com"]}
        path = tmp_path / "multi.vcf"
        write_vcard(path, data)

        parsed = parse_vcard(path)
        assert len(parsed["email"]) == 2

    def test_tags_roundtrip(self, tmp_path: Path):
        """First-class tags should roundtrip through write/parse."""
        data = {
            "fn": "Tagged Person",
            "tags": ["dev", "friend"],
        }
        path = tmp_path / "tagged.vcf"
        write_vcard(path, data)

        parsed = parse_vcard(path)
        assert parsed["tags"] == ["dev", "friend"]
        # Should also appear in x_fields for backward compatibility
        assert "X-ICARUS-TAGS" in parsed["x_fields"]

    def test_tags_from_x_fields(self, tmp_path: Path):
        """Tags set via x_fields should appear in first-class tags list."""
        data = {
            "fn": "X-Field Tags",
            "x_fields": {"X-ICARUS-TAGS": "alpha, beta"},
        }
        path = tmp_path / "xfield-tags.vcf"
        write_vcard(path, data)

        parsed = parse_vcard(path)
        assert parsed["tags"] == ["alpha", "beta"]

    def test_empty_vcf(self, tmp_path: Path):
        path = tmp_path / "empty.vcf"
        path.write_text("BEGIN:VCARD\nVERSION:4.0\nEND:VCARD\n")
        parsed = parse_vcard(path)
        # Should not error, fn may be empty
        assert parsed["_path"] == path
        assert parsed["tags"] == []


class TestSearchContacts:
    @pytest.fixture
    def contacts_dir(self, tmp_path: Path) -> Path:
        d = tmp_path / "contacts"
        d.mkdir()
        # Create test contacts
        create_contact(d, {"fn": "Alice Smith", "email": ["alice@example.com"], "org": "Acme"})
        create_contact(d, {"fn": "Bob Jones", "email": ["bob@test.org"]})
        create_contact(d, {"fn": "Charlie Acme", "org": "Acme Corp"})
        return d

    def test_search_by_name(self, contacts_dir: Path):
        results = search_contacts(contacts_dir, "alice")
        assert len(results) >= 1
        assert results[0]["fn"] == "Alice Smith"

    def test_search_by_email(self, contacts_dir: Path):
        results = search_contacts(contacts_dir, "bob@test")
        assert len(results) >= 1
        assert results[0]["fn"] == "Bob Jones"

    def test_search_by_org(self, contacts_dir: Path):
        results = search_contacts(contacts_dir, "acme")
        assert len(results) >= 2  # Alice (org=Acme) and Charlie (org=Acme Corp, fn=Acme)

    def test_search_all(self, contacts_dir: Path):
        results = search_contacts(contacts_dir, "")
        assert len(results) == 3

    def test_search_no_match(self, contacts_dir: Path):
        results = search_contacts(contacts_dir, "zzzznotfound")
        assert len(results) == 0

    def test_search_nonexistent_dir(self, tmp_path: Path):
        results = search_contacts(tmp_path / "nope", "test")
        assert results == []


class TestCreateContact:
    def test_creates_file(self, tmp_path: Path):
        d = tmp_path / "contacts"
        d.mkdir()
        path = create_contact(d, {"fn": "New Person", "email": ["new@test.com"]})
        assert path.exists()
        assert path.name == "new-person.vcf"

    def test_no_overwrite(self, tmp_path: Path):
        d = tmp_path / "contacts"
        d.mkdir()
        p1 = create_contact(d, {"fn": "Same Name"})
        p2 = create_contact(d, {"fn": "Same Name"})
        assert p1 != p2
        assert p1.exists()
        assert p2.exists()

    def test_creates_dir_if_missing(self, tmp_path: Path):
        d = tmp_path / "new_contacts"
        path = create_contact(d, {"fn": "Auto Dir"})
        assert path.exists()
        assert d.exists()


class TestUpdateContact:
    def test_updates_existing(self, tmp_path: Path):
        d = tmp_path / "contacts"
        d.mkdir()
        create_contact(d, {"fn": "Update Me", "email": ["old@test.com"]})
        update_contact(d, "update-me", {"email": ["new@test.com"]})

        parsed = parse_vcard(d / "update-me.vcf")
        assert "new@test.com" in parsed["email"]

    def test_clear_tags_with_empty_list(self, tmp_path: Path):
        d = tmp_path / "contacts"
        d.mkdir()
        create_contact(d, {"fn": "Tag Test", "tags": ["old-tag"]})
        update_contact(d, "tag-test", {"tags": []})
        parsed = parse_vcard(d / "tag-test.vcf")
        assert parsed["tags"] == []

    def test_update_contact_rejects_path_traversal(self, tmp_path: Path):
        d = tmp_path / "contacts"
        d.mkdir()
        with pytest.raises(ValueError, match="Invalid contact slug"):
            update_contact(d, "../evil", {"fn": "hacker"})

    def test_raises_on_missing(self, tmp_path: Path):
        d = tmp_path / "contacts"
        d.mkdir()
        with pytest.raises(FileNotFoundError):
            update_contact(d, "nonexistent", {"fn": "nope"})
