#!/usr/bin/env python3
"""Tests for MarketplaceManager class (marketplace registry management)"""

import json
from pathlib import Path

import pytest

from skill_seekers.services.marketplace_manager import MarketplaceManager


@pytest.fixture
def temp_config_dir(tmp_path):
    config_dir = tmp_path / "test_config"
    config_dir.mkdir()
    return config_dir


@pytest.fixture
def manager(temp_config_dir):
    return MarketplaceManager(config_dir=str(temp_config_dir))


class TestMarketplaceManagerInit:
    def test_init_creates_config_dir(self, tmp_path):
        config_dir = tmp_path / "new_config"
        mgr = MarketplaceManager(config_dir=str(config_dir))
        assert config_dir.exists()
        assert mgr.config_dir == config_dir

    def test_init_creates_registry_file(self, temp_config_dir):
        _mgr = MarketplaceManager(config_dir=str(temp_config_dir))
        registry_file = temp_config_dir / "marketplaces.json"
        assert registry_file.exists()
        with open(registry_file) as f:
            data = json.load(f)
            assert data == {"version": "1.0", "marketplaces": []}

    def test_init_preserves_existing_registry(self, temp_config_dir):
        registry_file = temp_config_dir / "marketplaces.json"
        existing_data = {
            "version": "1.0",
            "marketplaces": [{"name": "test", "git_url": "https://example.com/repo.git"}],
        }
        with open(registry_file, "w") as f:
            json.dump(existing_data, f)
        _mgr = MarketplaceManager(config_dir=str(temp_config_dir))
        with open(registry_file) as f:
            data = json.load(f)
            assert len(data["marketplaces"]) == 1

    def test_init_with_default_config_dir(self):
        mgr = MarketplaceManager()
        assert mgr.config_dir == Path.home() / ".skill-seekers"


class TestAddMarketplace:
    def test_add_marketplace_minimal(self, manager):
        mp = manager.add_marketplace(
            name="spyke", git_url="https://github.com/spykegames/plugins.git"
        )
        assert mp["name"] == "spyke"
        assert mp["git_url"] == "https://github.com/spykegames/plugins.git"
        assert mp["token_env"] == "GITHUB_TOKEN"
        assert mp["branch"] == "main"
        assert mp["enabled"] is True
        assert mp["author"] == {"name": "", "email": ""}

    def test_add_marketplace_full_parameters(self, manager):
        author = {"name": "Spyke Team", "email": "team@spyke.com"}
        mp = manager.add_marketplace(
            name="spyke",
            git_url="https://github.com/spykegames/plugins.git",
            token_env="SPYKE_TOKEN",
            branch="develop",
            author=author,
            enabled=False,
        )
        assert mp["token_env"] == "SPYKE_TOKEN"
        assert mp["branch"] == "develop"
        assert mp["author"] == author
        assert mp["enabled"] is False

    def test_add_marketplace_normalizes_name(self, manager):
        mp = manager.add_marketplace(name="MyMarket", git_url="https://github.com/org/repo.git")
        assert mp["name"] == "mymarket"

    def test_add_marketplace_invalid_name_empty(self, manager):
        with pytest.raises(ValueError, match="Invalid marketplace name"):
            manager.add_marketplace(name="", git_url="https://github.com/org/repo.git")

    def test_add_marketplace_invalid_name_special_chars(self, manager):
        with pytest.raises(ValueError, match="Invalid marketplace name"):
            manager.add_marketplace(name="my@market", git_url="https://github.com/org/repo.git")

    def test_add_marketplace_valid_name_with_hyphens(self, manager):
        mp = manager.add_marketplace(name="my-market", git_url="https://github.com/org/repo.git")
        assert mp["name"] == "my-market"

    def test_add_marketplace_empty_git_url(self, manager):
        with pytest.raises(ValueError, match="git_url cannot be empty"):
            manager.add_marketplace(name="spyke", git_url="")

    def test_add_marketplace_strips_git_url(self, manager):
        mp = manager.add_marketplace(name="spyke", git_url="  https://github.com/org/repo.git  ")
        assert mp["git_url"] == "https://github.com/org/repo.git"

    def test_add_marketplace_updates_existing(self, manager):
        mp1 = manager.add_marketplace(name="spyke", git_url="https://github.com/org/repo1.git")
        mp2 = manager.add_marketplace(name="spyke", git_url="https://github.com/org/repo2.git")
        assert mp2["git_url"] == "https://github.com/org/repo2.git"
        assert mp2["added_at"] == mp1["added_at"]
        assert len(manager.list_marketplaces()) == 1

    def test_add_marketplace_persists_to_file(self, manager, temp_config_dir):
        manager.add_marketplace(name="spyke", git_url="https://github.com/org/repo.git")
        registry_file = temp_config_dir / "marketplaces.json"
        with open(registry_file) as f:
            data = json.load(f)
        assert len(data["marketplaces"]) == 1
        assert data["marketplaces"][0]["name"] == "spyke"


class TestGetMarketplace:
    def test_get_marketplace_exact_match(self, manager):
        manager.add_marketplace(name="spyke", git_url="https://github.com/org/repo.git")
        mp = manager.get_marketplace("spyke")
        assert mp["name"] == "spyke"

    def test_get_marketplace_case_insensitive(self, manager):
        manager.add_marketplace(name="Spyke", git_url="https://github.com/org/repo.git")
        mp = manager.get_marketplace("spyke")
        assert mp["name"] == "spyke"

    def test_get_marketplace_not_found(self, manager):
        with pytest.raises(KeyError, match="Marketplace 'nonexistent' not found"):
            manager.get_marketplace("nonexistent")

    def test_get_marketplace_not_found_shows_available(self, manager):
        manager.add_marketplace(name="mp1", git_url="https://example.com/1.git")
        manager.add_marketplace(name="mp2", git_url="https://example.com/2.git")
        with pytest.raises(KeyError, match="Available marketplaces: mp1, mp2"):
            manager.get_marketplace("mp3")

    def test_get_marketplace_empty_registry(self, manager):
        with pytest.raises(KeyError, match="Available marketplaces: none"):
            manager.get_marketplace("spyke")


class TestListMarketplaces:
    def test_list_marketplaces_empty(self, manager):
        assert manager.list_marketplaces() == []

    def test_list_marketplaces_multiple(self, manager):
        manager.add_marketplace(name="mp1", git_url="https://example.com/1.git")
        manager.add_marketplace(name="mp2", git_url="https://example.com/2.git")
        assert len(manager.list_marketplaces()) == 2

    def test_list_marketplaces_enabled_only(self, manager):
        manager.add_marketplace(name="enabled", git_url="https://example.com/1.git", enabled=True)
        manager.add_marketplace(name="disabled", git_url="https://example.com/2.git", enabled=False)
        marketplaces = manager.list_marketplaces(enabled_only=True)
        assert len(marketplaces) == 1
        assert marketplaces[0]["name"] == "enabled"


class TestRemoveMarketplace:
    def test_remove_marketplace_exists(self, manager):
        manager.add_marketplace(name="spyke", git_url="https://github.com/org/repo.git")
        assert manager.remove_marketplace("spyke") is True
        assert len(manager.list_marketplaces()) == 0

    def test_remove_marketplace_not_found(self, manager):
        assert manager.remove_marketplace("nonexistent") is False

    def test_remove_marketplace_persists_to_file(self, manager, temp_config_dir):
        manager.add_marketplace(name="mp1", git_url="https://example.com/1.git")
        manager.add_marketplace(name="mp2", git_url="https://example.com/2.git")
        manager.remove_marketplace("mp1")
        registry_file = temp_config_dir / "marketplaces.json"
        with open(registry_file) as f:
            data = json.load(f)
        assert len(data["marketplaces"]) == 1
        assert data["marketplaces"][0]["name"] == "mp2"


class TestUpdateMarketplace:
    def test_update_marketplace_git_url(self, manager):
        manager.add_marketplace(name="spyke", git_url="https://github.com/org/repo1.git")
        updated = manager.update_marketplace(
            name="spyke", git_url="https://github.com/org/repo2.git"
        )
        assert updated["git_url"] == "https://github.com/org/repo2.git"

    def test_update_marketplace_author(self, manager):
        manager.add_marketplace(name="spyke", git_url="https://github.com/org/repo.git")
        new_author = {"name": "New Author", "email": "new@example.com"}
        updated = manager.update_marketplace(name="spyke", author=new_author)
        assert updated["author"] == new_author

    def test_update_marketplace_updates_timestamp(self, manager):
        mp = manager.add_marketplace(name="spyke", git_url="https://github.com/org/repo.git")
        updated = manager.update_marketplace(name="spyke", branch="develop")
        assert updated["updated_at"] > mp["updated_at"]

    def test_update_marketplace_not_found(self, manager):
        with pytest.raises(KeyError, match="Marketplace 'nonexistent' not found"):
            manager.update_marketplace(name="nonexistent", branch="main")


class TestDefaultTokenEnv:
    def test_github_url(self, manager):
        mp = manager.add_marketplace(name="test", git_url="https://github.com/org/repo.git")
        assert mp["token_env"] == "GITHUB_TOKEN"

    def test_gitlab_url(self, manager):
        mp = manager.add_marketplace(name="test", git_url="https://gitlab.com/org/repo.git")
        assert mp["token_env"] == "GITLAB_TOKEN"

    def test_bitbucket_url(self, manager):
        mp = manager.add_marketplace(name="test", git_url="https://bitbucket.org/org/repo.git")
        assert mp["token_env"] == "BITBUCKET_TOKEN"

    def test_unknown_url(self, manager):
        mp = manager.add_marketplace(
            name="test", git_url="https://custom-git.example.com/org/repo.git"
        )
        assert mp["token_env"] == "GIT_TOKEN"

    def test_override_token_env(self, manager):
        mp = manager.add_marketplace(
            name="test",
            git_url="https://github.com/org/repo.git",
            token_env="MY_CUSTOM_TOKEN",
        )
        assert mp["token_env"] == "MY_CUSTOM_TOKEN"


class TestRegistryPersistence:
    def test_registry_atomic_write(self, manager, temp_config_dir):
        manager.add_marketplace(name="spyke", git_url="https://github.com/org/repo.git")
        assert len(list(temp_config_dir.glob("*.tmp"))) == 0

    def test_registry_corrupted_file(self, temp_config_dir):
        mgr = MarketplaceManager(config_dir=str(temp_config_dir))
        (temp_config_dir / "marketplaces.json").write_text("{ invalid json }")
        with pytest.raises(ValueError, match="Corrupted registry file"):
            mgr._read_registry()
