"""
Unit Tests für DSMS WebUI Funktionalität
Tests für die WebUI-bezogenen Endpoints und Datenstrukturen
"""

import pytest
import json
import hashlib
from unittest.mock import AsyncMock, patch, MagicMock
from fastapi.testclient import TestClient


# ==================== DSMS WebUI API Response Tests ====================

class TestDsmsWebUINodeInfo:
    """Tests für die Node-Info API die vom WebUI verwendet wird"""

    def test_node_info_response_structure(self):
        """Test: Node-Info Response hat alle WebUI-relevanten Felder"""
        # Diese Struktur wird vom WebUI erwartet
        expected_fields = [
            "node_id",
            "protocol_version",
            "agent_version",
            "repo_size",
            "storage_max",
            "num_objects",
            "addresses"
        ]

        # Mock response wie sie vom DSMS Gateway kommt
        mock_response = {
            "node_id": "QmTestNodeId123",
            "protocol_version": "ipfs/0.1.0",
            "agent_version": "kubo/0.24.0",
            "repo_size": 1048576,
            "storage_max": 10737418240,
            "num_objects": 42,
            "addresses": ["/ip4/127.0.0.1/tcp/4001"]
        }

        for field in expected_fields:
            assert field in mock_response, f"Feld {field} fehlt in der Response"

    def test_node_info_formats_repo_size(self):
        """Test: Repo-Größe wird korrekt formatiert"""
        def format_bytes(size_bytes):
            """Formatiert Bytes in lesbare Einheiten (wie im WebUI)"""
            if size_bytes is None:
                return "N/A"
            for unit in ['B', 'KB', 'MB', 'GB']:
                if size_bytes < 1024:
                    return f"{size_bytes:.1f} {unit}"
                size_bytes /= 1024
            return f"{size_bytes:.1f} TB"

        assert format_bytes(1024) == "1.0 KB"
        assert format_bytes(1048576) == "1.0 MB"
        assert format_bytes(1073741824) == "1.0 GB"
        assert format_bytes(None) == "N/A"


class TestDsmsWebUIDocumentList:
    """Tests für die Dokumentenlisten-API die vom WebUI verwendet wird"""

    def test_document_list_response_structure(self):
        """Test: Document List Response hat alle WebUI-relevanten Felder"""
        mock_response = {
            "documents": [
                {
                    "cid": "QmTestCid123",
                    "metadata": {
                        "document_type": "legal_document",
                        "document_id": "privacy-policy",
                        "version": "1.0",
                        "created_at": "2024-01-01T00:00:00"
                    },
                    "filename": "datenschutz.html"
                }
            ],
            "total": 1
        }

        assert "documents" in mock_response
        assert "total" in mock_response
        assert mock_response["total"] == len(mock_response["documents"])

        doc = mock_response["documents"][0]
        assert "cid" in doc
        assert "metadata" in doc

    def test_document_list_empty(self):
        """Test: Leere Dokumentenliste wird korrekt behandelt"""
        mock_response = {
            "documents": [],
            "total": 0
        }

        assert mock_response["total"] == 0
        assert len(mock_response["documents"]) == 0


class TestDsmsWebUIVerification:
    """Tests für die Verifizierungs-API die vom WebUI verwendet wird"""

    def test_verify_response_valid_integrity(self):
        """Test: Verifizierungs-Response bei gültiger Integrität"""
        content = "Test content"
        checksum = hashlib.sha256(content.encode('utf-8')).hexdigest()

        mock_response = {
            "cid": "QmTestCid123",
            "exists": True,
            "integrity_valid": True,
            "metadata": {
                "document_type": "legal_document",
                "checksum": checksum
            },
            "stored_checksum": checksum,
            "calculated_checksum": checksum,
            "verified_at": "2024-01-01T10:00:00"
        }

        assert mock_response["exists"] is True
        assert mock_response["integrity_valid"] is True
        assert mock_response["stored_checksum"] == mock_response["calculated_checksum"]

    def test_verify_response_invalid_integrity(self):
        """Test: Verifizierungs-Response bei ungültiger Integrität"""
        mock_response = {
            "cid": "QmTestCid123",
            "exists": True,
            "integrity_valid": False,
            "metadata": {
                "document_type": "legal_document"
            },
            "stored_checksum": "fake_checksum",
            "calculated_checksum": "real_checksum",
            "verified_at": "2024-01-01T10:00:00"
        }

        assert mock_response["exists"] is True
        assert mock_response["integrity_valid"] is False
        assert mock_response["stored_checksum"] != mock_response["calculated_checksum"]

    def test_verify_response_not_found(self):
        """Test: Verifizierungs-Response wenn Dokument nicht existiert"""
        mock_response = {
            "cid": "QmNonExistent",
            "exists": False,
            "error": "Dokument nicht gefunden",
            "verified_at": "2024-01-01T10:00:00"
        }

        assert mock_response["exists"] is False
        assert "error" in mock_response


class TestDsmsWebUIUpload:
    """Tests für die Upload-API die vom WebUI verwendet wird"""

    def test_upload_response_structure(self):
        """Test: Upload Response hat alle WebUI-relevanten Felder"""
        mock_response = {
            "cid": "QmNewDocCid123",
            "size": 1024,
            "metadata": {
                "document_type": "legal_document",
                "document_id": None,
                "version": None,
                "language": "de",
                "created_at": "2024-01-01T10:00:00",
                "checksum": "abc123def456",
                "encrypted": False
            },
            "gateway_url": "http://dsms-node:8080/ipfs/QmNewDocCid123",
            "timestamp": "2024-01-01T10:00:00"
        }

        assert "cid" in mock_response
        assert "size" in mock_response
        assert "gateway_url" in mock_response
        assert mock_response["cid"].startswith("Qm")

    def test_checksum_calculation(self):
        """Test: Checksum wird korrekt berechnet (wie im Gateway)"""
        content = b"Test document content"
        expected_checksum = hashlib.sha256(content).hexdigest()

        # Simuliert die Checksum-Berechnung wie im DSMS Gateway
        calculated = hashlib.sha256(content).hexdigest()

        assert calculated == expected_checksum
        assert len(calculated) == 64  # SHA-256 hat immer 64 Hex-Zeichen


class TestDsmsWebUIHealthCheck:
    """Tests für den Health Check der vom WebUI verwendet wird"""

    def test_health_response_online(self):
        """Test: Health Response wenn Node online ist"""
        mock_response = {
            "status": "healthy",
            "ipfs_connected": True,
            "timestamp": "2024-01-01T10:00:00"
        }

        assert mock_response["status"] == "healthy"
        assert mock_response["ipfs_connected"] is True

    def test_health_response_offline(self):
        """Test: Health Response wenn Node offline ist"""
        mock_response = {
            "status": "degraded",
            "ipfs_connected": False,
            "timestamp": "2024-01-01T10:00:00"
        }

        assert mock_response["status"] == "degraded"
        assert mock_response["ipfs_connected"] is False


class TestDsmsWebUIDataTransformation:
    """Tests für Daten-Transformationen die das WebUI durchführt"""

    def test_format_timestamp(self):
        """Test: ISO-Timestamp wird für Anzeige formatiert"""
        def format_timestamp(iso_string):
            """Formatiert ISO-Timestamp für die Anzeige"""
            from datetime import datetime
            try:
                dt = datetime.fromisoformat(iso_string.replace('Z', '+00:00'))
                return dt.strftime("%d.%m.%Y %H:%M")
            except:
                return iso_string

        assert format_timestamp("2024-01-15T10:30:00") == "15.01.2024 10:30"
        assert format_timestamp("invalid") == "invalid"

    def test_truncate_cid(self):
        """Test: CID wird für Anzeige gekürzt"""
        def truncate_cid(cid, max_length=20):
            """Kürzt CID für die Anzeige"""
            if len(cid) <= max_length:
                return cid
            return cid[:8] + "..." + cid[-8:]

        long_cid = "QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG"
        truncated = truncate_cid(long_cid)

        assert len(truncated) < len(long_cid)
        assert truncated.startswith("Qm")
        assert "..." in truncated

    def test_status_badge_class(self):
        """Test: Status-Badge-Klasse wird korrekt ermittelt"""
        def get_status_badge_class(status):
            """Gibt die CSS-Klasse für den Status zurück"""
            status_classes = {
                "healthy": "success",
                "degraded": "warning",
                "offline": "danger",
                True: "success",
                False: "danger"
            }
            return status_classes.get(status, "secondary")

        assert get_status_badge_class("healthy") == "success"
        assert get_status_badge_class("degraded") == "warning"
        assert get_status_badge_class(True) == "success"
        assert get_status_badge_class(False) == "danger"
        assert get_status_badge_class("unknown") == "secondary"


class TestDsmsWebUIErrorHandling:
    """Tests für die Fehlerbehandlung im WebUI"""

    def test_network_error_message(self):
        """Test: Netzwerkfehler wird benutzerfreundlich angezeigt"""
        def get_error_message(error_type, details=None):
            """Gibt benutzerfreundliche Fehlermeldung zurück"""
            messages = {
                "network": "DSMS Node ist nicht erreichbar. Bitte überprüfen Sie die Verbindung.",
                "auth": "Authentifizierung fehlgeschlagen. Bitte erneut anmelden.",
                "not_found": "Dokument nicht gefunden.",
                "upload": f"Upload fehlgeschlagen: {details}" if details else "Upload fehlgeschlagen.",
                "unknown": "Ein unbekannter Fehler ist aufgetreten."
            }
            return messages.get(error_type, messages["unknown"])

        assert "nicht erreichbar" in get_error_message("network")
        assert "nicht gefunden" in get_error_message("not_found")
        assert "Test Error" in get_error_message("upload", "Test Error")

    def test_validation_cid_format(self):
        """Test: CID-Format wird validiert"""
        def is_valid_cid(cid):
            """Prüft ob CID ein gültiges Format hat"""
            if not cid:
                return False
            # CIDv0 beginnt mit Qm und hat 46 Zeichen
            if cid.startswith("Qm") and len(cid) == 46:
                return True
            # CIDv1 beginnt mit b und ist base32 encoded
            if cid.startswith("b") and len(cid) > 40:
                return True
            return False

        assert is_valid_cid("QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG") is True
        assert is_valid_cid("bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi") is True
        assert is_valid_cid("invalid") is False
        assert is_valid_cid("") is False
        assert is_valid_cid(None) is False


class TestDsmsWebUIIntegration:
    """Integrationstests für WebUI-Workflows"""

    def test_upload_and_verify_workflow(self):
        """Test: Upload und anschließende Verifizierung"""
        # Simuliert den Upload-Workflow
        upload_content = b"Test document for verification"
        expected_checksum = hashlib.sha256(upload_content).hexdigest()

        # Upload Response
        upload_response = {
            "cid": "QmNewDoc123456789012345678901234567890123456",
            "size": len(upload_content),
            "metadata": {
                "checksum": expected_checksum
            }
        }

        # Verifizierung
        verify_response = {
            "cid": upload_response["cid"],
            "exists": True,
            "integrity_valid": True,
            "stored_checksum": expected_checksum,
            "calculated_checksum": expected_checksum
        }

        assert verify_response["integrity_valid"] is True
        assert verify_response["stored_checksum"] == upload_response["metadata"]["checksum"]

    def test_node_status_determines_ui_state(self):
        """Test: Node-Status bestimmt UI-Zustand"""
        def get_ui_state(health_response):
            """Ermittelt UI-Zustand basierend auf Health Check"""
            if health_response.get("ipfs_connected"):
                return {
                    "status": "online",
                    "upload_enabled": True,
                    "explore_enabled": True,
                    "message": None
                }
            else:
                return {
                    "status": "offline",
                    "upload_enabled": False,
                    "explore_enabled": False,
                    "message": "DSMS Node ist nicht erreichbar"
                }

        online_state = get_ui_state({"ipfs_connected": True, "status": "healthy"})
        assert online_state["upload_enabled"] is True

        offline_state = get_ui_state({"ipfs_connected": False, "status": "degraded"})
        assert offline_state["upload_enabled"] is False
        assert offline_state["message"] is not None


# ==================== Run Tests ====================

if __name__ == "__main__":
    pytest.main([__file__, "-v"])
