import pytest
from django.core.exceptions import ImproperlyConfigured
from django.db import models

from djino.models import SyncModel
from djino.registry import djinoRegistry
from djino.sync_meta import SyncScope


class TestRegistry:
    def test_autodiscover_finds_sync_models(self):
        djinoRegistry.autodiscover()
        found = djinoRegistry.get_models()
        assert "testapp.Note" in found
        assert "testapp.Tag" in found
        assert "testapp.SharedNote" in found
        assert "testapp.DefaultsModel" in found

    def test_autodiscover_ignores_abstract_models(self):
        djinoRegistry.autodiscover()
        found = djinoRegistry.get_models()
        # SyncModel itself is abstract, should not be registered
        for key in found:
            assert "SyncModel" not in key

    def test_parses_global_scope(self):
        djinoRegistry.autodiscover()
        meta = djinoRegistry.get_meta("testapp.Tag")
        assert meta.scope == SyncScope.GLOBAL
        assert meta.client_writable is False

    def test_parses_user_scope(self):
        djinoRegistry.autodiscover()
        meta = djinoRegistry.get_meta("testapp.Note")
        assert meta.scope == SyncScope.USER
        assert meta.owner_field == "author"

    def test_parses_shared_scope(self):
        djinoRegistry.autodiscover()
        meta = djinoRegistry.get_meta("testapp.SharedNote")
        assert meta.scope == SyncScope.SHARED
        assert meta.sync_filter is not None
        assert meta.client_writable is True
        assert meta.write_check is not None

    def test_validates_shared_requires_sync_filter(self):
        class BadShared(SyncModel):
            class Meta:
                app_label = "testapp"

            class SyncMeta:
                scope = SyncScope.SHARED

        with pytest.raises(ImproperlyConfigured, match="SHARED scope requires sync_filter"):
            djinoRegistry._parse_sync_meta(BadShared)

    def test_validates_user_requires_owner_field(self):
        class BadUser(SyncModel):
            class Meta:
                app_label = "testapp"

            class SyncMeta:
                scope = SyncScope.USER

        with pytest.raises(ImproperlyConfigured, match="USER scope requires owner_field"):
            djinoRegistry._parse_sync_meta(BadUser)

    def test_validates_global_rejects_client_writable(self):
        class BadGlobal(SyncModel):
            class Meta:
                app_label = "testapp"

            class SyncMeta:
                scope = SyncScope.GLOBAL
                client_writable = True

        with pytest.raises(
            ImproperlyConfigured, match="GLOBAL scope should not be client_writable"
        ):
            djinoRegistry._parse_sync_meta(BadGlobal)

    def test_validates_owner_field_exists(self):
        class BadOwner(SyncModel):
            class Meta:
                app_label = "testapp"

            class SyncMeta:
                scope = SyncScope.USER
                owner_field = "nonexistent"

        with pytest.raises(ImproperlyConfigured, match="owner_field 'nonexistent'"):
            djinoRegistry._parse_sync_meta(BadOwner)

    def test_model_without_sync_meta_gets_defaults(self):
        class NoMeta(SyncModel):
            name = models.CharField(max_length=100)
            owner = models.ForeignKey("auth.User", on_delete=models.CASCADE)

            class Meta:
                app_label = "testapp"

        meta = djinoRegistry._parse_sync_meta(NoMeta)
        assert meta.scope == SyncScope.USER
        assert meta.client_writable is True
        assert meta.sync_filter is None
