"""
Admin Dashboard Backend Extension Entry Point
Provides administrative operations and data aggregation for the GGG system.
"""

import base64
import csv
import json
import traceback
from datetime import datetime
from io import StringIO
from typing import Any, Dict, List

import ggg
from kybra_simple_db import Entity
from kybra_simple_logging import get_logger

from .models import RegistrationCode

logger = get_logger("extensions.admin_dashboard")


def extension_sync_call(method_name: str, args: dict):
    """
    Synchronous extension API calls for admin operations
    """
    # Method mapping with argument requirements
    methods = {
        "import_data": (import_data, True),
        "export_data": (export_data, True),
        "generate_registration_url": (generate_registration_url, True),
        "validate_registration_code": (validate_registration_code, True),
        "get_registration_codes": (get_registration_codes, True),
    }

    if method_name not in methods:
        return {"success": False, "error": f"Unknown method: {method_name}"}

    function, requires_args = methods[method_name]

    try:
        if requires_args:
            return function(args)
        else:
            return function()
    except Exception as e:
        return {"success": False, "error": f"Error calling {method_name}: {str(e)}"}


def export_data(args):
    """
    Export all data from the realm (entities and codexes)
    """
    try:
        # Parse args if it's a JSON string
        if isinstance(args, str):
            args = json.loads(args)

        entity_types = args.get("entity_types", None)
        include_codexes = args.get("include_codexes", True)

        logger.debug(
            f"Exporting data - entity_types: {entity_types}, include_codexes: {include_codexes}"
        )

        # Get all entity classes from ggg module
        all_entities = []
        codexes = []

        # List of known entity types in the system
        entity_classes = [
            "User",
            "Human",
            "Member",
            "Organization",
            "Realm",
            "Treasury",
            "Instrument",
            "Transfer",
            "Balance",
            "Mandate",
            "Contract",
            "Trade",
            "Dispute",
            "License",
            "Task",
            "Codex",
            "TaskSchedule",
            "TaskExecution",
            "Land",
            "Registry",
            "Service",
            "Proposal",
            "Vote",
            "Invoice",
            "Notification",
            "Identity",
            "UserProfile",
            "Permission",
        ]

        # Filter entity classes if specific types requested
        if entity_types:
            entity_classes = [ec for ec in entity_classes if ec in entity_types]

        # Export each entity type
        for entity_class_name in entity_classes:
            try:
                # Get the entity class from ggg module
                if hasattr(ggg, entity_class_name):
                    entity_class = getattr(ggg, entity_class_name)

                    # Get all instances of this entity type
                    instances = list(entity_class.instances())

                    logger.debug(
                        f"Found {len(instances)} instances of {entity_class_name}"
                    )

                    for instance in instances:
                        try:
                            # Serialize the entity
                            serialized = instance.serialize()

                            # Separate codexes from regular entities
                            if entity_class_name == "Codex" and include_codexes:
                                codexes.append(
                                    {
                                        "name": serialized.get("name", ""),
                                        "code": serialized.get("code", ""),
                                        "_id": serialized.get("_id", ""),
                                    }
                                )
                            else:
                                all_entities.append(serialized)
                        except Exception as e:
                            logger.error(
                                f"Error serializing {entity_class_name} instance: {str(e)}"
                            )
                            continue

            except Exception as e:
                logger.error(
                    f"Error processing entity class {entity_class_name}: {str(e)}"
                )
                continue

        # Prepare response data
        response_data = {
            "entities": all_entities,
            "codexes": codexes,
            "total_entities": len(all_entities),
            "total_codexes": len(codexes),
        }

        # Serialize to JSON string for transport
        data_json = json.dumps(response_data)

        logger.debug(
            f"Export complete - {len(all_entities)} entities, {len(codexes)} codexes"
        )

        return {
            "success": True,
            "message": f"Successfully exported {len(all_entities)} entities and {len(codexes)} codexes",
            "data": data_json,
        }

    except Exception as e:
        logger.error(f"Error exporting data: {e}\n{traceback.format_exc()}")
        return {"success": False, "error": str(e)}


def import_data(args):
    """
    Import data from direct data input
    """
    try:
        # Parse args if it's a JSON string
        if isinstance(args, str):
            # Handle base64 encoded args to avoid shell escaping issues
            if args.startswith("base64:"):
                import base64

                args = base64.b64decode(args[7:]).decode("utf-8")
            args = json.loads(args)

        data_format = args.get("format", "json")
        data_content = args.get("data", "")

        logger.debug(f"data_content: {data_content}")
        logger.debug(f"data_format: {data_format}")

        if not data_content:
            return {"success": False, "error": "No data provided"}

        # Parse data based on format
        parsed_data = []
        if data_format == "csv":
            # Handle CSV data
            import io

            csv_reader = csv.DictReader(
                io.StringIO(data_content)
            )  # TODO: this might not work on Kybra
            parsed_data = list(csv_reader)
        else:
            # Handle JSON data
            try:
                if isinstance(data_content, str):
                    parsed_data = json.loads(data_content)
                else:
                    parsed_data = data_content

                if not isinstance(parsed_data, list):
                    parsed_data = [parsed_data]
            except json.JSONDecodeError as e:
                return {"success": False, "error": f"Invalid JSON data: {str(e)}"}

        # Process data in batches
        logger.debug(f"parsed_data: {parsed_data}")
        results = process_bulk_import(parsed_data)

        return {
            "success": True,
            "message": "Successfully imported records",
            "data": {
                "total_records": len(parsed_data),
                "successful": results["successful"],
                "failed": results["failed"],
                "errors": results["errors"],
            },
        }

    except Exception as e:
        logger.error(f"Error processing import data: {e}\n{traceback.format_exc()}")
        return {"success": False, "error": str(e)}


def process_bulk_import(data: List[Dict[str, Any]]) -> Dict[str, Any]:
    """Process bulk import data and create entities"""
    successful = 0
    failed = 0
    errors = []

    logger.debug(f"data: {data}")

    for record in data:
        try:

            entity = Entity.deserialize(record)

            # Example data
            # d = [
            #     {
            #         'timestamp_created': '2025-09-12 23:17:07.522',
            #         'timestamp_updated': '2025-09-12 23:17:07.522',
            #         'creator': 'system', 'updater': 'system', 'owner': 'system',
            #         '_type': 'Realm', '_id': '1',
            #         'name': 'Generated Demo Realm',
            #         'description': 'Generated demo realm with 51 citizens and 5 organizations',
            #         'id': '0',
            #         'created_at': '2025-09-12T23:17:07.522028',
            #         'status': 'active',
            #         'governance_type': 'democratic',
            #         'population': 51,
            #         'organization_count': 5,
            #         'settings': {'voting_period_days': 7, 'proposal_threshold': 0.1, 'quorum_percentage': 0.3, 'tax_rate': 0.15, 'ubi_amount': 1000},
            #         'treasury': '1'}, {'timestamp_created': '2025-09-12 23:17:07.522', 'timestamp_updated': '2025-09-12 23:17:07.522', 'creator': 'system', 'updater': 'system', 'owner': 'system', '_type': 'Treasury', '_id': '1', 'name': 'Generated Demo Realm Treasury', 'vault_principal_id': None, 'created_at': '2025-09-12T23:17:07.522258', 'updated_at': '2025-09-12T23:17:07.522261', 'realm': '1'}, {'timestamp_created': '2025-09-12 23:17:07.521', 'timestamp_updated': '2025-09-12 23:17:07.521', 'creator': 'system', 'updater': 'system', 'owner': 'system', '_type': 'UserProfile', '_id': '1', 'name': 'admin', 'description': 'Admin user profile', 'allowed_to': 'a,l,l'}, {'timestamp_created': '2025-09-12 23:17:07.521', 'timestamp_updated': '2025-09-12 23:17:07.521', 'creator': 'system', 'updater': 'system', 'owner': 'system', '_type': 'UserProfile', '_id': '2', 'name': 'member', 'description': 'Member user profile', 'allowed_to': ''
            #         }
            #     ]

            entity = Entity.deserialize(record)
            entity_type = record["_type"]
            if entity_type == "Codex":
                if record["code"].startswith("base64:"):
                    entity.code = base64.b64decode(record["code"][7:]).decode()
                else:
                    entity.code = record["code"]

            successful += 1
        except Exception as e:
            logger.error(f"Error creating entity: {str(e)}\n{traceback.format_exc()}")
            failed += 1
            errors.append(f"Record {record}: {str(e)}")

    return {
        "successful": successful,
        "failed": failed,
        "errors": errors[:10],  # Limit to first 10 errors
    }


def generate_registration_url(args: dict):
    """Generate a registration URL for a user"""
    try:
        user_id = args.get("user_id")
        created_by = args.get("created_by", "admin")
        frontend_url = args.get("frontend_url", "https://localhost:3000")
        email = args["email"]
        expires_in_hours = args.get("expires_in_hours", 24)

        if not user_id:
            return {"success": False, "error": "user_id is required"}

        # Create registration code
        reg_code = RegistrationCode.create(
            user_id=user_id,
            created_by=created_by,
            frontend_url=frontend_url,
            email=email,
            expires_in_hours=expires_in_hours,
        )

        return {
            "success": True,
            "data": {
                "code": reg_code.code,
                "registration_url": reg_code.registration_url,
                "expires_at": datetime.fromtimestamp(reg_code.expires_at).isoformat(),
                "user_id": reg_code.user_id,
            },
        }
    except Exception as e:
        return {"success": False, "error": str(e)}


def validate_registration_code(args: dict):
    """Validate a registration code"""
    try:
        code = args.get("code")
        if not code:
            return {"success": False, "error": "code is required"}

        # Find registration code
        reg_code = RegistrationCode.find_by_code(code)
        if not reg_code:
            return {"success": False, "error": "Invalid registration code"}

        # Check if valid
        if not reg_code.is_valid():
            current_timestamp = int(datetime.utcnow().timestamp())
            reason = (
                "expired" if reg_code.expires_at < current_timestamp else "already used"
            )
            return {"success": False, "error": f"Registration code is {reason}"}

        return {
            "success": True,
            "data": {
                "user_id": reg_code.user_id,
                "email": reg_code.email,
                "expires_at": datetime.fromtimestamp(reg_code.expires_at).isoformat(),
                "created_by": reg_code.created_by,
            },
        }
    except Exception as e:
        return {"success": False, "error": str(e)}


def get_registration_codes(args: dict):
    """Get registration codes with optional filtering"""
    try:
        user_id = args.get("user_id")
        include_used = args.get("include_used", False)

        if user_id:
            codes = RegistrationCode.find_by_user_id(user_id)
        else:
            codes = RegistrationCode.instances()

        # Filter out used codes if requested
        if not include_used:
            codes = [code for code in codes if code.used == 0]

        return {
            "success": True,
            "data": [
                {
                    "code": code.code,
                    "user_id": code.user_id,
                    "email": code.email,
                    "registration_url": code.registration_url,
                    "expires_at": datetime.fromtimestamp(code.expires_at).isoformat(),
                    "used": code.used == 1,
                    "used_at": (
                        datetime.fromtimestamp(code.used_at).isoformat()
                        if code.used_at > 0
                        else None
                    ),
                    "created_by": code.created_by,
                    "is_valid": code.is_valid(),
                }
                for code in codes
            ],
        }
    except Exception as e:
        return {"success": False, "error": str(e)}
