"""
Identify where members keep assets in space and flag hostile owners.

The routines below are used both for the HTML renderings and faux-alerts
that can be sent when a user has assets in systems owned by enemies.
"""

from allianceauth.authentication.models import CharacterOwnership
from allianceauth.services.hooks import get_extension_logger
from django.contrib.auth.models import User
from ..app_settings import (
    get_system_owner,
    is_nullsec,
    is_player_structure,
    get_safe_entities,
    resolve_location_name,
    resolve_location_system_id,
    is_highsec,
    is_lowsec,
    corptools_active,
    is_hostile_unified,
    is_ship,
)
from django.utils import timezone
from ..models import BigBrotherConfig
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from typing import List, Optional, Dict

logger = get_extension_logger(__name__)

try:
    if corptools_active():
        from corptools.models import CharacterAudit, CharacterAsset, EveLocation
    else:
        CharacterAudit = None
        CharacterAsset = None
        EveLocation = None
except ImportError:
    CharacterAudit = None
    CharacterAsset = None
    EveLocation = None


def _parse_id_list(value: Optional[str]) -> set[int]:
    if not value:
        return set()
    return {int(x) for x in value.split(",") if x.strip().isdigit()}


def get_asset_locations(user_id: int) -> Dict[int, dict]:
    """
    Return a dict mapping system IDs to a dict containing their name and a list of locations
    (stations/structures) where any of the given user's characters has one or more assets.
    """
    if not corptools_active() or CharacterAudit is None:
        return {}
    try:
        user = User.objects.get(pk=user_id)
    except User.DoesNotExist:
        return {}

    system_map: Dict[int, dict] = {}
    _loc_sys_cache = {}
    _loc_name_cache = {}

    def add_asset(system_obj, location_id, location_name, char_id, char_name, type_id, type_name):
        """Store the asset details organized by system and location."""
        key = None
        sys_name = None

        if system_obj:
            key = getattr(system_obj, "pk", None)
            sys_name = system_obj.name
        elif location_id:
            # Attempt to resolve system name
            if location_id in _loc_sys_cache:
                key = _loc_sys_cache[location_id]
            else:
                key = resolve_location_system_id(location_id)
                _loc_sys_cache[location_id] = key

            if key:
                if key in _loc_name_cache:
                    sys_name = _loc_name_cache[key]
                else:
                    sys_name = resolve_location_name(key)
                    _loc_name_cache[key] = sys_name

        if not key:
            return

        if key not in system_map:
            system_map[key] = {"name": sys_name, "locations": {}}

        # Determine location name to use as key/label
        loc_key = location_id or 0
        if loc_key not in system_map[key]["locations"]:
            if location_name:
                resolved_loc_name = location_name
            else:
                if loc_key in _loc_name_cache:
                    resolved_loc_name = _loc_name_cache[loc_key]
                else:
                    resolved_loc_name = resolve_location_name(loc_key) or f"Unknown Location {loc_key}"
                    _loc_name_cache[loc_key] = resolved_loc_name

            system_map[key]["locations"][loc_key] = {
                "name": resolved_loc_name,
                "assets": [],
            }

        system_map[key]["locations"][loc_key]["assets"].append({
            "char_id": char_id,
            "char_name": char_name,
            "type_id": type_id,
            "type_name": type_name,
        })

    # for each EVE character owned by this user
    for co in CharacterOwnership.objects.filter(user=user).select_related("character"):
        try:
            char_audit = CharacterAudit.objects.get(character=co.character)
        except CharacterAudit.DoesNotExist:
            continue

        assets = (
            CharacterAsset.objects.select_related(
                "location_name__system",
                "type_name__group__category",
            )
            .filter(character=char_audit)
            .exclude(location_flag__iexact="solar_system")
        )

        for asset in assets:
            if (asset.location_flag or "").lower() == "assetsafety":
                continue

            loc = asset.location_name
            system_obj = getattr(loc, "system", None) if loc else None

            # Optimization: use cached name from select_related if available
            loc_name = None
            if loc:
                loc_name = loc.location_name

            if not loc_name:
                loc_key = asset.location_id
                if loc_key in _loc_name_cache:
                    loc_name = _loc_name_cache[loc_key]
                else:
                    loc_name = resolve_location_name(loc_key)
                    _loc_name_cache[loc_key] = loc_name

            if not asset.type_name:
                continue

            add_asset(
                system_obj, asset.location_id, loc_name,
                co.character.character_id, co.character.character_name,
                asset.type_name.type_id, asset.type_name.name
            )

    return system_map


def get_hostile_asset_locations(user_id: int) -> Dict[str, dict]:
    """
    Returns a mapping of system display name -> structured hostile data
    for systems where the user's characters have assets in space and the
    system is considered hostile under the unified processor logic.
    """
    systems = get_asset_locations(user_id)
    if not systems:
        return {}

    hostile_map: Dict[str, dict] = {}
    from ..app_settings import get_safe_entities
    safe_entities = get_safe_entities()
    _hostile_memo = {}

    for system_id, data in systems.items():
        system_name = data.get("name")
        display_name = system_name or f"Unknown ({system_id})"

        # We need the system owner info for the summary
        owner_info = get_system_owner({"id": system_id, "name": display_name})
        oname = owner_info.get("owner_name", "Unresolvable") if owner_info else "Unresolvable"
        rname = owner_info.get("region_name", "Unknown Region") if owner_info else "Unknown Region"

        system_has_hostile = False
        # structured data: list of records
        records = []

        # Check each location in this system
        for loc_id, loc_data in data.get("locations", {}).items():
            loc_name = loc_data["name"]

            # Map of char_name -> set of ships for this specific location
            char_ships_at_loc = {}
            location_has_hostile = False

            for asset in loc_data.get("assets", []):
                # Memoize check results for character+location+type
                memo_key = (asset["char_id"], loc_id, system_id, asset["type_id"])
                if memo_key in _hostile_memo:
                    is_hostile = _hostile_memo[memo_key]
                else:
                    # Use unified check for each asset
                    is_hostile = is_hostile_unified(
                        involved_ids=[asset["char_id"]],
                        location_id=loc_id,
                        system_id=system_id,
                        is_asset=True,
                        asset_type_id=asset["type_id"],
                        when=timezone.now(),
                        safe_entities=safe_entities
                    )
                    _hostile_memo[memo_key] = is_hostile

                if is_hostile:
                    system_has_hostile = True
                    location_has_hostile = True
                    cname = asset["char_name"]
                    if is_ship(asset["type_id"]):
                        char_ships_at_loc.setdefault(cname, set()).add(asset["type_name"])
                    else:
                        # Ensure character is recorded even if no ships (e.g. just modules/items)
                        char_ships_at_loc.setdefault(cname, set())

            if location_has_hostile:
                for cname, ships in char_ships_at_loc.items():
                    records.append({
                        "char_name": cname,
                        "location_name": loc_name,
                        "ships": sorted(list(ships))
                    })

        if system_has_hostile:
            hostile_map[display_name] = {
                "owner": oname,
                "region": rname,
                "records": records
            }
            logger.info(f"Hostile asset system: {display_name} owned by {oname}")

    return hostile_map



def render_assets(user_id: int) -> Optional[str]:
    """
    Returns an HTML table listing each system where the user's characters have assets,
    the system's sovereign owner, and highlights in red any asset considered hostile.
    """
    try:
        systems = get_asset_locations(user_id)
        if not systems:
            return None

        rows: List[Dict] = []
        from ..app_settings import get_safe_entities
        safe_entities = get_safe_entities()
        _hostile_memo = {}

        for system_id, data in systems.items():
            system_name = data.get("name")
            display_name = system_name or f"Unknown ({system_id})"

            # Base system owner info for the table
            owner_info = get_system_owner({"id": system_id, "name": display_name})
            oname = owner_info.get("owner_name", "Unresolvable") if owner_info else "Unresolvable"
            region_name = owner_info.get("region_name", "Unknown Region") if owner_info else "Unknown Region"

            # Iterate locations inside system
            for loc_id, loc_data in data.get("locations", {}).items():
                loc_name = loc_data["name"]

                # Check each asset group (char/type combo)
                # Actually we can group by char for rendering
                char_assets = {}
                for asset in loc_data.get("assets", []):
                    char_name = asset["char_name"]
                    if char_name not in char_assets:
                        char_assets[char_name] = {"ships": [], "is_hostile": False, "char_id": asset["char_id"]}

                    # Memoize check results for character+location+type
                    memo_key = (asset["char_id"], loc_id, system_id, asset["type_id"])
                    if memo_key in _hostile_memo:
                        is_hostile = _hostile_memo[memo_key]
                    else:
                        # Check if this specific asset is hostile
                        is_hostile = is_hostile_unified(
                            involved_ids=[asset["char_id"]],
                            location_id=loc_id,
                            system_id=system_id,
                            is_asset=True,
                            asset_type_id=asset["type_id"],
                            when=timezone.now(),
                            safe_entities=safe_entities
                        )
                        _hostile_memo[memo_key] = is_hostile

                    if is_hostile:
                        char_assets[char_name]["is_hostile"] = True
                        if is_ship(asset["type_id"]):
                            char_assets[char_name]["ships"].append(asset["type_name"])

                for char_name, cdata in char_assets.items():
                    ship_str = ", ".join(sorted(cdata["ships"])) if cdata["ships"] else ""
                    rows.append({
                        "system": display_name,
                        "location": loc_name,
                        "character": char_name,
                        "owner": oname,
                        "region": region_name,
                        "hostile": cdata["is_hostile"],
                        "ships": ship_str,
                    })

        if not rows:
            return "<p>No hostile assets found.</p>"

        # Sort rows: hostile first, then by system, location, character
        rows.sort(key=lambda x: (not x["hostile"], x["system"], x["location"], x["character"]))

        html_output = '<table class="table table-striped table-hover stats">'
        html_output += (
            '<thead>'
            '  <tr>'
            '      <th style="width: 15%">System</th>'
            '      <th style="width: 20%">Station</th>'
            '      <th style="width: 15%">Character</th>'
            '      <th style="width: 15%">Owner</th>'
            '      <th style="width: 15%">Region</th>'
            '      <th style="width: 20%">Hostile Asset</th>'
            '  </tr>'
            '</thead>'
            '<tbody>'
        )

        for row in rows:
            system_cell = row["system"]
            owner_cell = row["owner"]
            region_cell = row["region"]
            hostile_ship = row["ships"] if row["hostile"] else ""

            if row["hostile"]:
                owner_cell = mark_safe(f'<span class="text-danger">{owner_cell}</span>')

            html_output += format_html(
                '   <tr>'
                '       <td>{}</td>'
                '       <td>{}</td>'
                '       <td>{}</td>'
                '       <td>{}</td>'
                '       <td>{}</td>'
                '       <td>{}</td>'
                '   </tr>',
                system_cell,
                row["location"],
                row["character"],
                owner_cell,
                region_cell,
                hostile_ship,
            )

        html_output += '</tbody></table>'
        return html_output
    except Exception as e:
        logger.exception(f"Error rendering assets for user {user_id}")
        return f"<p class='text-danger'>Error rendering assets: {str(e)}</p>"
