"""Tests for alumni models."""
from datetime import datetime, timezone

from django.test import SimpleTestCase, TestCase

from allianceauth.eveonline.models import (
    EveAllianceInfo, EveCharacter, EveCorporationInfo,
)

from alumni.models import (
    AlumniSetup, CharacterCorporationHistory, CharacterUpdateTimestamp,
    CorporationAllianceHistory, CorporationUpdateTimestamp,
)


class AlumniSetupModelTest(SimpleTestCase):
    """Test AlumniSetup singleton model."""

    def test_alumni_setup_is_singleton(self) -> None:
        """Verify AlumniSetup is a singleton model."""
        self.assertEqual(AlumniSetup._meta.model.__bases__[0].__name__, "SingletonModel")

    def test_alumni_corporations_field_exists(self) -> None:
        """Verify alumni_corporations ManyToMany field exists."""
        field = AlumniSetup._meta.get_field("alumni_corporations")
        self.assertEqual(field.__class__.__name__, "ManyToManyField")
        self.assertEqual(field.related_model, EveCorporationInfo)

    def test_alumni_alliances_field_exists(self) -> None:
        """Verify alumni_alliances ManyToMany field exists."""
        field = AlumniSetup._meta.get_field("alumni_alliances")
        self.assertEqual(field.__class__.__name__, "ManyToManyField")
        self.assertEqual(field.related_model, EveAllianceInfo)

    def test_alumni_corporations_blank(self) -> None:
        """Verify alumni_corporations field allows blank."""
        field = AlumniSetup._meta.get_field("alumni_corporations")
        self.assertTrue(field.blank)

    def test_alumni_alliances_blank(self) -> None:
        """Verify alumni_alliances field allows blank."""
        field = AlumniSetup._meta.get_field("alumni_alliances")
        self.assertTrue(field.blank)


class CorporationUpdateTimestampModelTest(SimpleTestCase):
    """Test CorporationUpdateTimestamp model."""

    def test_corporation_id_field_unique(self) -> None:
        """Verify corporation_id field is unique."""
        field = CorporationUpdateTimestamp._meta.get_field("corporation_id")
        self.assertTrue(field.unique)

    def test_corporation_id_field_is_positive_integer(self) -> None:
        """Verify corporation_id is PositiveIntegerField."""
        field = CorporationUpdateTimestamp._meta.get_field("corporation_id")
        self.assertEqual(field.__class__.__name__, "PositiveIntegerField")

    def test_last_updated_field_auto_now(self) -> None:
        """Verify last_updated is auto_now DateTimeField."""
        field = CorporationUpdateTimestamp._meta.get_field("last_updated")
        self.assertTrue(field.auto_now)

    def test_verbose_name(self) -> None:
        """Verify verbose_name is set."""
        self.assertEqual(
            CorporationUpdateTimestamp._meta.verbose_name,
            "Corporation Update Timestamp"
        )

    def test_verbose_name_plural(self) -> None:
        """Verify verbose_name_plural is set."""
        self.assertEqual(
            CorporationUpdateTimestamp._meta.verbose_name_plural,
            "Corporation Update Timestamps"
        )


class CharacterUpdateTimestampModelTest(SimpleTestCase):
    """Test CharacterUpdateTimestamp model."""

    def test_character_field_is_one_to_one(self) -> None:
        """Verify character field is OneToOneField."""
        field = CharacterUpdateTimestamp._meta.get_field("character")
        self.assertEqual(field.__class__.__name__, "OneToOneField")

    def test_character_field_cascade_delete(self) -> None:
        """Verify character field cascades on delete."""
        field = CharacterUpdateTimestamp._meta.get_field("character")
        self.assertEqual(field.remote_field.on_delete.__name__, "CASCADE")

    def test_last_updated_field_auto_now(self) -> None:
        """Verify last_updated is auto_now DateTimeField."""
        field = CharacterUpdateTimestamp._meta.get_field("last_updated")
        self.assertTrue(field.auto_now)

    def test_verbose_name(self) -> None:
        """Verify verbose_name is set."""
        self.assertEqual(
            CharacterUpdateTimestamp._meta.verbose_name,
            "Character Update Timestamp"
        )


class CorporationAllianceHistoryModelTest(SimpleTestCase):
    """Test CorporationAllianceHistory model."""

    def test_corporation_id_field_db_indexed(self) -> None:
        """Verify corporation_id field has db_index."""
        field = CorporationAllianceHistory._meta.get_field("corporation_id")
        self.assertTrue(field.db_index)

    def test_alliance_id_field_nullable_and_indexed(self) -> None:
        """Verify alliance_id field is nullable and indexed."""
        field = CorporationAllianceHistory._meta.get_field("alliance_id")
        self.assertTrue(field.null)
        self.assertTrue(field.blank)
        self.assertTrue(field.db_index)

    def test_is_deleted_field_default_false(self) -> None:
        """Verify is_deleted defaults to False."""
        field = CorporationAllianceHistory._meta.get_field("is_deleted")
        self.assertFalse(field.default)

    def test_record_id_field_exists(self) -> None:
        """Verify record_id PositiveIntegerField exists."""
        field = CorporationAllianceHistory._meta.get_field("record_id")
        self.assertEqual(field.__class__.__name__, "PositiveIntegerField")

    def test_start_date_field_is_datetime(self) -> None:
        """Verify start_date is DateTimeField."""
        field = CorporationAllianceHistory._meta.get_field("start_date")
        self.assertEqual(field.__class__.__name__, "DateTimeField")

    def test_unique_constraint_exists(self) -> None:
        """Verify unique constraint on corporation_id and record_id."""
        constraints = CorporationAllianceHistory._meta.constraints
        constraint_names = [c.name for c in constraints]
        self.assertIn("CorporationAllianceRecord", constraint_names)


class CharacterCorporationHistoryModelTest(SimpleTestCase):
    """Test CharacterCorporationHistory model."""

    def test_character_field_is_foreign_key(self) -> None:
        """Verify character field is ForeignKey."""
        field = CharacterCorporationHistory._meta.get_field("character")
        self.assertEqual(field.__class__.__name__, "ForeignKey")

    def test_character_field_cascade_delete(self) -> None:
        """Verify character field cascades on delete."""
        field = CharacterCorporationHistory._meta.get_field("character")
        self.assertEqual(field.remote_field.on_delete.__name__, "CASCADE")

    def test_corporation_id_field_is_positive_integer(self) -> None:
        """Verify corporation_id is PositiveIntegerField."""
        field = CharacterCorporationHistory._meta.get_field("corporation_id")
        self.assertEqual(field.__class__.__name__, "PositiveIntegerField")

    def test_is_deleted_field_default_false(self) -> None:
        """Verify is_deleted defaults to False."""
        field = CharacterCorporationHistory._meta.get_field("is_deleted")
        self.assertFalse(field.default)

    def test_record_id_field_exists(self) -> None:
        """Verify record_id PositiveIntegerField exists."""
        field = CharacterCorporationHistory._meta.get_field("record_id")
        self.assertEqual(field.__class__.__name__, "PositiveIntegerField")

    def test_start_date_field_is_datetime(self) -> None:
        """Verify start_date is DateTimeField."""
        field = CharacterCorporationHistory._meta.get_field("start_date")
        self.assertEqual(field.__class__.__name__, "DateTimeField")

    def test_unique_constraint_exists(self) -> None:
        """Verify unique constraint on character and record_id."""
        constraints = CharacterCorporationHistory._meta.constraints
        constraint_names = [c.name for c in constraints]
        self.assertIn("CharacterCorporationRecord", constraint_names)


class CorporationAllianceHistoryIntegrationTest(TestCase):
    """Integration tests for CorporationAllianceHistory model."""

    def test_create_corporation_alliance_history(self) -> None:
        """Test creating a CorporationAllianceHistory record."""
        history = CorporationAllianceHistory.objects.create(
            corporation_id=98765432,
            alliance_id=123456789,
            is_deleted=False,
            record_id=1,
            start_date=datetime.now(timezone.utc),
        )
        self.assertIsNotNone(history.id)
        self.assertEqual(history.corporation_id, 98765432)
        self.assertEqual(history.alliance_id, 123456789)

    def test_corporation_alliance_history_with_null_alliance(self) -> None:
        """Test CorporationAllianceHistory with null alliance_id."""
        history = CorporationAllianceHistory.objects.create(
            corporation_id=98765432,
            alliance_id=None,
            is_deleted=False,
            record_id=1,
            start_date=datetime.now(timezone.utc),
        )
        self.assertIsNone(history.alliance_id)

    def test_corporation_alliance_history_unique_constraint(self) -> None:
        """Test unique constraint on corporation_id and record_id."""
        start_date = datetime.now(timezone.utc)
        CorporationAllianceHistory.objects.create(
            corporation_id=98765432,
            alliance_id=123456789,
            is_deleted=False,
            record_id=1,
            start_date=start_date,
        )
        # Duplicate record with same corporation_id and record_id should violate constraint
        with self.assertRaises(Exception):  # IntegrityError
            CorporationAllianceHistory.objects.create(
                corporation_id=98765432,
                alliance_id=987654321,
                is_deleted=False,
                record_id=1,
                start_date=start_date,
            )


class CharacterCorporationHistoryIntegrationTest(TestCase):
    """Integration tests for CharacterCorporationHistory model."""

    def setUp(self) -> None:
        """Set up test fixtures."""
        self.character = EveCharacter.objects.create(
            character_id=12345678,
            character_name="Test Character",
            corporation_id=98765432,
            corporation_name="Test Corp",
        )

    def test_create_character_corporation_history(self) -> None:
        """Test creating a CharacterCorporationHistory record."""
        history = CharacterCorporationHistory.objects.create(
            character=self.character,
            corporation_id=98765432,
            is_deleted=False,
            record_id=1,
            start_date=datetime.now(timezone.utc),
        )
        self.assertIsNotNone(history.id)
        self.assertEqual(history.character, self.character)
        self.assertEqual(history.corporation_id, 98765432)

    def test_character_corporation_history_cascade_delete(self) -> None:
        """Test cascade delete when character is deleted."""
        CharacterCorporationHistory.objects.create(
            character=self.character,
            corporation_id=98765432,
            is_deleted=False,
            record_id=1,
            start_date=datetime.now(timezone.utc),
        )
        self.assertEqual(CharacterCorporationHistory.objects.count(), 1)
        self.character.delete()
        self.assertEqual(CharacterCorporationHistory.objects.count(), 0)

    def test_character_corporation_history_unique_constraint(self) -> None:
        """Test unique constraint on character and record_id."""
        start_date = datetime.now(timezone.utc)
        CharacterCorporationHistory.objects.create(
            character=self.character,
            corporation_id=98765432,
            is_deleted=False,
            record_id=1,
            start_date=start_date,
        )
        # Duplicate record with same character and record_id should violate constraint
        with self.assertRaises(Exception):  # IntegrityError
            CharacterCorporationHistory.objects.create(
                character=self.character,
                corporation_id=987654321,
                is_deleted=False,
                record_id=1,
                start_date=start_date,
            )


class CorporationUpdateTimestampIntegrationTest(TestCase):
    """Integration tests for CorporationUpdateTimestamp model."""

    def test_create_and_update_corporation_timestamp(self) -> None:
        """Test creating and updating a CorporationUpdateTimestamp."""
        timestamp, created = CorporationUpdateTimestamp.objects.update_or_create(
            corporation_id=98765432,
            defaults={"last_updated": datetime.now(timezone.utc)},
        )
        self.assertTrue(created)
        self.assertEqual(timestamp.corporation_id, 98765432)

        # Update it
        old_time = timestamp.last_updated
        timestamp, created = CorporationUpdateTimestamp.objects.update_or_create(
            corporation_id=98765432,
            defaults={"last_updated": datetime.now(timezone.utc)},
        )
        self.assertFalse(created)
        # Verify that last_updated is auto_now field (should be more recent or same)
        self.assertGreaterEqual(timestamp.last_updated, old_time)


class CharacterUpdateTimestampIntegrationTest(TestCase):
    """Integration tests for CharacterUpdateTimestamp model."""

    def setUp(self) -> None:
        """Set up test fixtures."""
        self.character = EveCharacter.objects.create(
            character_id=12345678,
            character_name="Test Character",
            corporation_id=98765432,
            corporation_name="Test Corp",
        )

    def test_create_and_update_character_timestamp(self) -> None:
        """Test creating and updating a CharacterUpdateTimestamp."""
        timestamp, created = CharacterUpdateTimestamp.objects.update_or_create(
            character=self.character,
            defaults={"last_updated": datetime.now(timezone.utc)},
        )
        self.assertTrue(created)
        self.assertEqual(timestamp.character, self.character)

        # Update it
        old_time = timestamp.last_updated
        timestamp, created = CharacterUpdateTimestamp.objects.update_or_create(
            character=self.character,
            defaults={"last_updated": datetime.now(timezone.utc)},
        )
        self.assertFalse(created)
        # Verify that last_updated is auto_now field (should be more recent or same)
        self.assertGreaterEqual(timestamp.last_updated, old_time)

    def test_character_timestamp_cascade_delete(self) -> None:
        """Test cascade delete when character is deleted."""
        CharacterUpdateTimestamp.objects.create(
            character=self.character,
            last_updated=datetime.now(timezone.utc),
        )
        self.assertEqual(CharacterUpdateTimestamp.objects.count(), 1)
        self.character.delete()
        self.assertEqual(CharacterUpdateTimestamp.objects.count(), 0)
