"""Storefront EVE SSO (login/logout + buyer identity) tests."""

from django.test import RequestFactory, TestCase
from django.urls import reverse

from shop.models import HULL, HullListing, Shop
from shop.tests.test_stock import make_owner_character, make_ship_type
from shop.tests.test_views_backoffice import no_manifest_static
from shop.views.storefront import _buyer_context


class BuyerContextTests(TestCase):
    def setUp(self):
        self.factory = RequestFactory()

    def _request_with_session(self, session_data=None):
        request = self.factory.get("/shop/pub/")
        from django.contrib.sessions.backends.db import SessionStore

        request.session = SessionStore()
        if session_data:
            for key, value in session_data.items():
                request.session[key] = value
        return request

    def test_anonymous_returns_none(self):
        ctx = _buyer_context(self._request_with_session())
        self.assertEqual(ctx, {"buyer": None})

    def test_buyer_gets_derived_portrait(self):
        request = self._request_with_session(
            {"shop_buyer": {"id": 90000001, "name": "Jane Pilot"}}
        )
        ctx = _buyer_context(request)
        self.assertEqual(ctx["buyer"]["id"], 90000001)
        self.assertEqual(ctx["buyer"]["name"], "Jane Pilot")
        self.assertIn("90000001", ctx["buyer"]["portrait"])
        self.assertIn("images.evetech.net", ctx["buyer"]["portrait"])


@no_manifest_static
class LogoutTests(TestCase):
    def setUp(self):
        self.user, self.char = make_owner_character()
        self.ship = make_ship_type()
        self.shop = Shop.objects.create(
            slug="pub",
            name="Pub",
            created_by=self.user,
            is_published=True,
            enabled_sections=[HULL],
        )
        HullListing.objects.create(shop=self.shop, eve_type=self.ship, price=0, stock=0)

    def test_logout_clears_session_and_redirects(self):
        session = self.client.session
        session["shop_buyer"] = {"id": 90000001, "name": "Jane Pilot"}
        session.save()
        resp = self.client.get(
            reverse("storefront:logout", args=["pub"]), SERVER_NAME="localhost"
        )
        self.assertEqual(resp.status_code, 302)
        self.assertEqual(resp["Location"], reverse("storefront:detail", args=["pub"]))
        self.assertNotIn("shop_buyer", self.client.session)

    def test_logout_when_not_logged_in_is_noop_redirect(self):
        resp = self.client.get(
            reverse("storefront:logout", args=["pub"]), SERVER_NAME="localhost"
        )
        self.assertEqual(resp.status_code, 302)
        self.assertEqual(resp["Location"], reverse("storefront:detail", args=["pub"]))


class FakeToken:
    """Stand-in for esi.models.Token — only the attributes our view reads."""

    def __init__(self, character_id=90000001, character_name="Jane Pilot"):
        self.character_id = character_id
        self.character_name = character_name
        self.deleted = False

    def delete(self):
        self.deleted = True


class LoginViewBodyTests(TestCase):
    def setUp(self):
        self.factory = RequestFactory()

    def _request(self):
        from django.contrib.sessions.backends.db import SessionStore

        request = self.factory.get("/shop/pub/login/")
        request.session = SessionStore()
        return request

    def test_login_stores_identity_deletes_token_and_redirects(self):
        from shop.views.storefront import login

        request = self._request()
        token = FakeToken()
        resp = login.__wrapped__(request, token, slug="pub")
        self.assertEqual(
            request.session["shop_buyer"], {"id": 90000001, "name": "Jane Pilot"}
        )
        self.assertTrue(token.deleted)
        self.assertEqual(resp.status_code, 302)
        self.assertEqual(resp["Location"], reverse("storefront:detail", args=["pub"]))


class UrlHookExclusionTests(TestCase):
    def test_login_and_logout_are_public(self):
        from shop.auth_hooks import register_storefront_urls

        hook = register_storefront_urls()
        self.assertIn("shop.views.storefront.login", hook.excluded_views)
        self.assertIn("shop.views.storefront.logout", hook.excluded_views)


@no_manifest_static
class HeaderUITests(TestCase):
    def setUp(self):
        self.user, self.char = make_owner_character()
        self.ship = make_ship_type()
        self.shop = Shop.objects.create(
            slug="pub",
            name="Pub",
            created_by=self.user,
            is_published=True,
            enabled_sections=[HULL],
        )
        HullListing.objects.create(shop=self.shop, eve_type=self.ship, price=0, stock=0)

    def _login_session(self):
        session = self.client.session
        session["shop_buyer"] = {"id": 90000001, "name": "Jane Pilot"}
        session.save()

    def test_anonymous_sees_login_link(self):
        resp = self.client.get("/shop/pub/hulls/", SERVER_NAME="localhost")
        self.assertContains(resp, "Login with EVE")
        self.assertContains(resp, reverse("storefront:login", args=["pub"]))
        self.assertNotContains(resp, "Logout")

    def test_authenticated_sees_portrait_name_and_logout(self):
        self._login_session()
        resp = self.client.get("/shop/pub/hulls/", SERVER_NAME="localhost")
        self.assertContains(resp, "Jane Pilot")
        self.assertContains(resp, "images.evetech.net/characters/90000001")
        self.assertContains(resp, reverse("storefront:logout", args=["pub"]))
        self.assertNotContains(resp, "Login with EVE")

    def test_header_present_on_item_detail_too(self):
        self._login_session()
        listing = HullListing.objects.get(shop=self.shop, eve_type=self.ship)
        url = reverse("storefront:item", args=["pub", listing.pk])
        resp = self.client.get(url, SERVER_NAME="localhost")
        self.assertContains(resp, "Jane Pilot")
