"""Guard against tenants operating on the platform owner's Addons account.

The bug: ProviderAddons() with no api_key fell back to config.ADDONS_API_KEY —
the owner's seller account. Every request-path caller omitted the key, so a tenant
pressing Sync imported the owner's threads, and ticket_post could publish a
tenant's reply onto an owner thread.

These tests pin the two properties that prevent it:
  1. an org's provider carries THAT org's key
  2. an org with no key raises instead of quietly getting someone else's
"""
import pytest

from supporthub.app.config import config
from supporthub.app.providers.addons import ProviderAddons
from supporthub.app.services.provider_factory import (
    MissingAddonsKey,
    decrypt_addons_key,
    provider_for_org,
)


class FakeOrg:
    def __init__(self, id=1, key_plain=None):
        self.id = id
        self.addons_api_key_encrypted = _encrypt(key_plain) if key_plain else None


def _encrypt(plain):
    from supporthub.app.onboarding.routes import _encrypt as enc
    return enc(plain)


def test_encrypt_decrypt_roundtrip_is_text_not_bytea_hex():
    """The column is Text: storing bytes wrote '\\x67...' and never decrypted."""
    token = _encrypt("secret-key-123")
    assert isinstance(token, str)
    assert not token.startswith("\\x")
    assert decrypt_addons_key(FakeOrg(key_plain="secret-key-123")) == "secret-key-123"


def test_provider_carries_the_orgs_own_key():
    org = FakeOrg(id=7, key_plain="tenant-seven-key")
    assert provider_for_org(org).key == "tenant-seven-key"


def test_two_orgs_get_two_different_keys():
    a = provider_for_org(FakeOrg(id=1, key_plain="key-a"))
    b = provider_for_org(FakeOrg(id=2, key_plain="key-b"))
    assert a.key != b.key


def test_org_without_a_key_raises_instead_of_borrowing_the_global_one():
    """The whole point: absence of a key must STOP the operation."""
    with pytest.raises(MissingAddonsKey):
        provider_for_org(FakeOrg(id=99, key_plain=None))


def test_org_without_a_key_does_not_silently_get_the_owner_key():
    """Belt and braces: assert the failure is not the owner's key leaking."""
    try:
        p = provider_for_org(FakeOrg(id=99, key_plain=None))
    except MissingAddonsKey:
        return
    assert p.key != config.ADDONS_API_KEY, "tenant received the OWNER's Addons key"


def test_none_org_raises():
    with pytest.raises(MissingAddonsKey):
        provider_for_org(None)


def test_seller_path_is_enforced_however_base_url_is_passed():
    """A bare host must still reach /request/seller, or every call 404s."""
    for base in (None, "https://api-addons.prestashop.com",
                 "https://api-addons.prestashop.com/",
                 "https://api-addons.prestashop.com/request/seller"):
        p = ProviderAddons(api_key="k", base_url=base)
        assert p.base_url.endswith("/request/seller")
        assert p.base_url.count("/request/seller") == 1


def test_order_sync_service_does_not_build_a_provider_on_its_own():
    """CSV import / profile rebuild need no API; they must not acquire a key.

    Eagerly building ProviderAddons() here is what gave DB-only operations the
    owner's credentials for free.
    """
    from supporthub.app.services.order_sync_service import OrderSyncService
    svc = OrderSyncService()
    assert svc.provider is None
    with pytest.raises(MissingAddonsKey):
        svc._api()


def test_every_org_in_the_database_has_its_own_key():
    """Integration: no org may be relying on the global fallback."""
    from sqlalchemy import text
    from supporthub.app.db import engine
    with engine.connect() as c:
        rows = c.execute(text(
            "SELECT id, slug, addons_api_key_encrypted FROM public.organizations"
        )).fetchall()
    if not rows:
        pytest.skip("no organizations provisioned")
    missing = [f"{r.id}:{r.slug}" for r in rows if not r.addons_api_key_encrypted]
    assert not missing, (
        f"orgs with no Addons key would fall back to the owner's account: {missing}"
    )
