"""
BizNode Agent Registry Service
==============================
Manages agent registration, CA verification workflow, and public registry.

Flow:
  1. Agent submitted -> listed as "unverified"
  2. Verification form emailed to ca@1bz.biz
  3. CA reviews and replies with VERIFIED/REJECTED
  4. BizNode processes email -> updates status
  5. Registry at https://registry.1bz.biz/ shows verified badge
"""

import json
import logging
import os
import random
import re
import string
import sys
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional

_PROJECT_ROOT = str(Path(__file__).resolve().parent.parent)
if _PROJECT_ROOT not in sys.path:
    sys.path.insert(0, _PROJECT_ROOT)

from memory.database import get_connection
from services.email_service import EmailService

log = logging.getLogger(__name__)

# Verification fee
VERIFICATION_FEE_AMOUNT = 10.0
VERIFICATION_FEE_CURRENCY = "BZeUSD"


def _generate_agent_id() -> str:
    """Generate a unique agent ID like BZAG-A1B2C."""
    chars = string.ascii_uppercase + string.digits
    suffix = "".join(random.choices(chars, k=5))
    return f"BZAG-{suffix}"


class AgentRegistryService:
    """Manages the BizNode Agent Registry with CA verification."""

    def __init__(self, db_path: str = None):
        self.db_path = db_path
        self.email_service = EmailService()
        self.email_service._email_type = "agent_registry"

    # ------------------------------------------------------------------
    # Registration
    # ------------------------------------------------------------------

    def register_agent(
        self,
        agent_name: str,
        owner_name: str,
        owner_email: str,
        owner_type: str = "individual",
        description: str = None,
        endpoint: str = None,
        capabilities: list = None,
        legal_entity_name: str = None,
        registration_number: str = None,
        country: str = None,
        telegram_bot_username: str = None,
        website_url: str = None,
        node_id: str = None,
    ) -> Dict[str, Any]:
        """Register a new agent. Auto-generates agent_id, lists as unverified,
        and sends verification form to ca@1bz.biz."""
        agent_id = _generate_agent_id()
        now = datetime.utcnow().isoformat()
        caps_json = json.dumps(capabilities) if capabilities else None

        conn = get_connection()
        cursor = conn.cursor()
        try:
            cursor.execute(
                """INSERT INTO agent_registry
                   (agent_id, agent_name, agent_description, agent_endpoint,
                    agent_capabilities, owner_name, owner_email, owner_type,
                    legal_entity_name, registration_number, country,
                    verification_status, submitted_at, updated_at,
                    listed_publicly, node_id, telegram_bot_username, website_url)
                   VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""",
                (
                    agent_id, agent_name, description, endpoint,
                    caps_json, owner_name, owner_email, owner_type,
                    legal_entity_name, registration_number, country,
                    "unverified", now, now,
                    1, node_id, telegram_bot_username, website_url,
                ),
            )
            conn.commit()
        except Exception as exc:
            conn.close()
            log.error("Failed to register agent: %s", exc)
            return {"success": False, "error": str(exc)}
        conn.close()

        # Note: verification requires separate request_verification() call with 10 BZeUSD payment
        log.info("Agent %s registered as unverified. Verification requires %s %s payment.",
                 agent_id, VERIFICATION_FEE_AMOUNT, VERIFICATION_FEE_CURRENCY)

        return {"success": True, "agent_id": agent_id}

    # ------------------------------------------------------------------
    # Queries
    # ------------------------------------------------------------------

    def get_agent(self, agent_id: str) -> Optional[Dict]:
        """Get agent details by ID."""
        conn = get_connection()
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM agent_registry WHERE agent_id = ?", (agent_id,))
        row = cursor.fetchone()
        conn.close()
        if row:
            d = dict(row)
            if d.get("agent_capabilities"):
                try:
                    d["agent_capabilities"] = json.loads(d["agent_capabilities"])
                except (json.JSONDecodeError, TypeError):
                    pass
            return d
        return None

    def list_agents(
        self, status: str = None, owner_type: str = None
    ) -> List[Dict]:
        """List all agents, optionally filtered by status/owner_type."""
        conn = get_connection()
        cursor = conn.cursor()
        query = "SELECT * FROM agent_registry WHERE listed_publicly = 1"
        params: list = []
        if status:
            query += " AND verification_status = ?"
            params.append(status)
        if owner_type:
            query += " AND owner_type = ?"
            params.append(owner_type)
        query += " ORDER BY submitted_at DESC"
        cursor.execute(query, params)
        rows = cursor.fetchall()
        conn.close()
        agents = []
        for row in rows:
            d = dict(row)
            if d.get("agent_capabilities"):
                try:
                    d["agent_capabilities"] = json.loads(d["agent_capabilities"])
                except (json.JSONDecodeError, TypeError):
                    pass
            agents.append(d)
        return agents

    # ------------------------------------------------------------------
    # CA Verification
    # ------------------------------------------------------------------

    def verify_agent(
        self, agent_id: str, ca_reference: str, ca_certificate_id: str = None
    ) -> Dict[str, Any]:
        """Mark agent as verified by CA."""
        now = datetime.utcnow().isoformat()
        conn = get_connection()
        cursor = conn.cursor()
        cursor.execute(
            """UPDATE agent_registry
               SET verification_status = 'verified',
                   verification_date = ?,
                   ca_reference = ?,
                   ca_certificate_id = ?,
                   updated_at = ?
               WHERE agent_id = ?""",
            (now, ca_reference, ca_certificate_id, now, agent_id),
        )
        affected = cursor.rowcount
        conn.commit()
        conn.close()
        if affected:
            return {"success": True, "agent_id": agent_id, "status": "verified"}
        return {"success": False, "error": "Agent not found"}

    def reject_agent(self, agent_id: str, reason: str = None) -> Dict[str, Any]:
        """Mark agent as rejected by CA."""
        now = datetime.utcnow().isoformat()
        conn = get_connection()
        cursor = conn.cursor()
        cursor.execute(
            """UPDATE agent_registry
               SET verification_status = 'rejected',
                   ca_reference = ?,
                   updated_at = ?
               WHERE agent_id = ?""",
            (reason or "Rejected by CA", now, agent_id),
        )
        affected = cursor.rowcount
        conn.commit()
        conn.close()
        if affected:
            return {"success": True, "agent_id": agent_id, "status": "rejected"}
        return {"success": False, "error": "Agent not found"}

    def update_agent(self, agent_id: str, **kwargs) -> Dict[str, Any]:
        """Update agent details."""
        allowed = {
            "agent_name", "agent_description", "agent_endpoint",
            "agent_capabilities", "owner_name", "owner_email", "owner_type",
            "legal_entity_name", "registration_number", "country",
            "listed_publicly", "telegram_bot_username", "website_url",
        }
        updates = {k: v for k, v in kwargs.items() if k in allowed}
        if not updates:
            return {"success": False, "error": "No valid fields to update"}
        if "agent_capabilities" in updates and isinstance(updates["agent_capabilities"], list):
            updates["agent_capabilities"] = json.dumps(updates["agent_capabilities"])
        updates["updated_at"] = datetime.utcnow().isoformat()

        set_clause = ", ".join(f"{k} = ?" for k in updates)
        values = list(updates.values()) + [agent_id]

        conn = get_connection()
        cursor = conn.cursor()
        cursor.execute(
            f"UPDATE agent_registry SET {set_clause} WHERE agent_id = ?", values
        )
        affected = cursor.rowcount
        conn.commit()
        conn.close()
        if affected:
            return {"success": True, "agent_id": agent_id}
        return {"success": False, "error": "Agent not found"}

    # ------------------------------------------------------------------
    # Verification Email Workflow
    # ------------------------------------------------------------------

    def send_verification_request(self, agent_id: str) -> Dict[str, Any]:
        """Send verification form email to ca@1bz.biz."""
        agent = self.get_agent(agent_id)
        if not agent:
            return {"success": False, "error": "Agent not found"}

        owner_type_label = (
            "Legal Entity" if agent["owner_type"] == "legal_entity" else "Individual"
        )
        capabilities = agent.get("agent_capabilities") or []
        if isinstance(capabilities, str):
            try:
                capabilities = json.loads(capabilities)
            except (json.JSONDecodeError, TypeError):
                capabilities = []
        caps_str = ", ".join(capabilities) if capabilities else "None specified"

        subject = f"BizNode Agent Verification Request - {agent_id}"

        plain_body = f"""BizNode Agent Verification Request
===================================

Agent ID: {agent_id}
Agent Name: {agent['agent_name']}
Description: {agent.get('agent_description') or 'N/A'}
Endpoint: {agent.get('agent_endpoint') or 'N/A'}
Capabilities: {caps_str}

OWNERSHIP DETAILS:
- Owner Type: {owner_type_label}
- Owner Name: {agent['owner_name']}
- Email: {agent['owner_email']}
- Legal Entity Name: {agent.get('legal_entity_name') or 'N/A'}
- Registration Number: {agent.get('registration_number') or 'N/A'}
- Country: {agent.get('country') or 'N/A'}

VERIFICATION ACTIONS:
To verify this agent, reply to this email with:
  VERIFIED - [CA Reference Number]

To reject, reply with:
  REJECTED - [Reason]

This is an automated request from BizNode Agent Registry.
Registry URL: https://registry.1bz.biz/
"""

        html_body = f"""<!DOCTYPE html>
<html>
<head>
<style>
  body {{ font-family: 'Segoe UI', Arial, sans-serif; background: #0A0D14; color: #E2E8F0; margin: 0; padding: 0; }}
  .container {{ max-width: 600px; margin: 0 auto; background: #111827; border-radius: 12px; overflow: hidden; }}
  .header {{ background: linear-gradient(135deg, #4F46E5, #7C3AED); padding: 28px 32px; }}
  .header h1 {{ margin: 0; font-size: 20px; color: #fff; }}
  .header p {{ margin: 6px 0 0; font-size: 13px; color: rgba(255,255,255,.7); }}
  .body {{ padding: 28px 32px; }}
  .section {{ margin-bottom: 24px; }}
  .section h3 {{ font-size: 12px; text-transform: uppercase; letter-spacing: .08em; color: #9CA3AF; margin-bottom: 12px; border-bottom: 1px solid #1F2937; padding-bottom: 8px; }}
  .row {{ display: flex; justify-content: space-between; padding: 6px 0; font-size: 14px; }}
  .row .label {{ color: #9CA3AF; }}
  .row .value {{ color: #E2E8F0; font-weight: 500; }}
  .badge {{ display: inline-block; padding: 3px 10px; border-radius: 999px; font-size: 11px; font-weight: 600; }}
  .badge-individual {{ background: rgba(59,130,246,.15); color: #60A5FA; }}
  .badge-entity {{ background: rgba(168,85,247,.15); color: #C084FC; }}
  .actions {{ background: #1F2937; border-radius: 8px; padding: 20px; margin-top: 20px; }}
  .actions h3 {{ margin-top: 0; color: #F59E0B; font-size: 14px; }}
  .actions code {{ background: #111827; padding: 4px 8px; border-radius: 4px; font-size: 13px; color: #34D399; }}
  .footer {{ padding: 16px 32px; text-align: center; font-size: 11px; color: #6B7280; border-top: 1px solid #1F2937; }}
</style>
</head>
<body>
<div class="container">
  <div class="header">
    <h1>Agent Verification Request</h1>
    <p>{agent_id} &mdash; Submitted {agent.get('submitted_at', '')[:10]}</p>
  </div>
  <div class="body">
    <div class="section">
      <h3>Agent Details</h3>
      <div class="row"><span class="label">Agent ID</span><span class="value">{agent_id}</span></div>
      <div class="row"><span class="label">Name</span><span class="value">{agent['agent_name']}</span></div>
      <div class="row"><span class="label">Description</span><span class="value">{agent.get('agent_description') or 'N/A'}</span></div>
      <div class="row"><span class="label">Endpoint</span><span class="value">{agent.get('agent_endpoint') or 'N/A'}</span></div>
      <div class="row"><span class="label">Capabilities</span><span class="value">{caps_str}</span></div>
    </div>
    <div class="section">
      <h3>Ownership Details</h3>
      <div class="row"><span class="label">Owner Type</span><span class="value"><span class="badge {'badge-entity' if agent['owner_type'] == 'legal_entity' else 'badge-individual'}">{owner_type_label}</span></span></div>
      <div class="row"><span class="label">Owner Name</span><span class="value">{agent['owner_name']}</span></div>
      <div class="row"><span class="label">Email</span><span class="value">{agent['owner_email']}</span></div>
      <div class="row"><span class="label">Legal Entity</span><span class="value">{agent.get('legal_entity_name') or 'N/A'}</span></div>
      <div class="row"><span class="label">Registration #</span><span class="value">{agent.get('registration_number') or 'N/A'}</span></div>
      <div class="row"><span class="label">Country</span><span class="value">{agent.get('country') or 'N/A'}</span></div>
    </div>
    <div class="actions">
      <h3>Verification Actions</h3>
      <p>To <strong>verify</strong> this agent, reply with:</p>
      <p><code>VERIFIED - [CA Reference Number]</code></p>
      <p>To <strong>reject</strong>, reply with:</p>
      <p><code>REJECTED - [Reason]</code></p>
    </div>
  </div>
  <div class="footer">
    BizNode Agent Registry &mdash; <a href="https://registry.1bz.biz/" style="color:#60A5FA;">registry.1bz.biz</a><br>
    &copy; {datetime.utcnow().year} 1BZ DZIT DAO LLC
  </div>
</div>
</body>
</html>"""

        result = self.email_service.send_email(
            to_email="ca@1bz.biz",
            subject=subject,
            body=plain_body,
            html=html_body,
        )
        return result

    def request_verification(self, agent_id: str, payment_tx_hash: str = "", payment_reference: str = "") -> Dict[str, Any]:
        """
        Request CA verification for an agent. Requires 10 BZeUSD payment.

        The agent must exist and be in 'unverified' status.
        Payment can be via BZeUSD tx hash or internal balance deduction.
        After payment confirmed, sends verification form to ca@1bz.biz.
        """
        agent = self.get_agent(agent_id)
        if not agent:
            return {"success": False, "error": "Agent not found"}

        if agent["verification_status"] == "verified":
            return {"success": False, "error": "Agent is already verified"}

        if agent["verification_status"] == "pending":
            return {"success": False, "error": "Verification already pending. Check with ca@1bz.biz"}

        # Check for payment — either tx hash or internal balance
        payment_confirmed = False

        if payment_tx_hash:
            # Verify on-chain payment
            try:
                from services.license_purchase_service import verify_polygon_transaction, BIZNODE_WALLET
                verified, info = verify_polygon_transaction(
                    payment_tx_hash,
                    expected_to=BIZNODE_WALLET,
                    expected_amount=VERIFICATION_FEE_AMOUNT,
                )
                if verified:
                    payment_confirmed = True
                else:
                    return {"success": False, "error": f"Payment verification failed: {info}"}
            except Exception as exc:
                return {"success": False, "error": f"Payment check error: {exc}"}

        elif payment_reference:
            # Internal balance deduction (for hosted agents with BZeUSD balance)
            try:
                from memory.database import get_connection
                conn = get_connection()
                cursor = conn.cursor()
                # Check if this agent has a hosted_agents entry with sufficient balance
                cursor.execute(
                    "SELECT bzeusd_balance FROM hosted_agents WHERE agent_id = ?",
                    (agent_id,),
                )
                row = cursor.fetchone()
                conn.close()
                if row and row[0] >= VERIFICATION_FEE_AMOUNT:
                    # Deduct balance
                    import importlib.util
                    spec = importlib.util.spec_from_file_location(
                        "_db", os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "memory", "database.py")
                    )
                    db = importlib.util.module_from_spec(spec)
                    spec.loader.exec_module(db)
                    db.adjust_agent_balance(agent_id, bzeusd_delta=-VERIFICATION_FEE_AMOUNT)
                    payment_confirmed = True
                else:
                    return {
                        "success": False,
                        "error": f"Insufficient BZeUSD balance. Need {VERIFICATION_FEE_AMOUNT} BZeUSD.",
                    }
            except Exception as exc:
                return {"success": False, "error": f"Balance check error: {exc}"}
        else:
            return {
                "success": False,
                "error": (
                    f"Verification requires {VERIFICATION_FEE_AMOUNT} {VERIFICATION_FEE_CURRENCY} payment. "
                    "Provide payment_tx_hash (on-chain) or payment_reference='balance' (deduct from account)."
                ),
            }

        if not payment_confirmed:
            return {"success": False, "error": "Payment not confirmed"}

        # Update status to pending
        now = datetime.utcnow().isoformat()
        conn = get_connection()
        cursor = conn.cursor()
        cursor.execute(
            """UPDATE agent_registry
               SET verification_status = 'pending',
                   ca_reference = ?,
                   updated_at = ?
               WHERE agent_id = ?""",
            (f"payment:{payment_tx_hash or 'balance'}", now, agent_id),
        )
        conn.commit()
        conn.close()

        # Send verification request to CA
        try:
            self.send_verification_request(agent_id)
        except Exception as exc:
            log.warning("Verification email failed for %s: %s", agent_id, exc)

        return {
            "success": True,
            "agent_id": agent_id,
            "status": "pending",
            "fee_charged": VERIFICATION_FEE_AMOUNT,
            "fee_currency": VERIFICATION_FEE_CURRENCY,
            "message": "Verification request sent to ca@1bz.biz. You will be notified once reviewed.",
        }

    def process_verification_email(
        self, email_subject: str, email_body: str, from_addr: str
    ) -> Dict[str, Any]:
        """Process incoming verification response from ca@1bz.biz.

        Looks for agent_id and VERIFIED/REJECTED in the email body.
        """
        # Validate sender
        if "ca@1bz.biz" not in from_addr.lower():
            return {"success": False, "error": "Email not from ca@1bz.biz"}

        # Extract agent_id from subject or body
        agent_match = re.search(r"(BZAG-[A-Z0-9]{5})", email_subject + " " + email_body)
        if not agent_match:
            return {"success": False, "error": "No agent ID found in email"}
        agent_id = agent_match.group(1)

        # Check agent exists
        agent = self.get_agent(agent_id)
        if not agent:
            return {"success": False, "error": f"Agent {agent_id} not found"}

        # Look for VERIFIED or REJECTED
        verified_match = re.search(
            r"VERIFIED\s*[-:]\s*(.+?)(?:\n|$)", email_body, re.I
        )
        rejected_match = re.search(
            r"REJECTED\s*[-:]\s*(.+?)(?:\n|$)", email_body, re.I
        )

        if verified_match:
            ca_ref = verified_match.group(1).strip()
            # Try to extract certificate ID if present
            cert_match = re.search(r"CERT[-_]?ID\s*[-:]\s*(\S+)", email_body, re.I)
            cert_id = cert_match.group(1) if cert_match else None
            result = self.verify_agent(agent_id, ca_ref, cert_id)
            log.info("Agent %s verified by CA. Ref: %s", agent_id, ca_ref)
            return result
        elif rejected_match:
            reason = rejected_match.group(1).strip()
            result = self.reject_agent(agent_id, reason)
            log.info("Agent %s rejected by CA. Reason: %s", agent_id, reason)
            return result
        else:
            return {
                "success": False,
                "error": "No VERIFIED or REJECTED keyword found in email",
            }

    # ------------------------------------------------------------------
    # Public Registry Data
    # ------------------------------------------------------------------

    def get_registry_data(self) -> List[Dict]:
        """Get all public agents formatted for the registry website."""
        agents = self.list_agents()
        registry = []
        for a in agents:
            badge = "unverified"
            badge_label = "Unverified"
            if a["verification_status"] == "verified":
                badge = "verified"
                badge_label = "CA Verified"
            elif a["verification_status"] == "pending":
                badge = "pending"
                badge_label = "Pending Verification"
            elif a["verification_status"] == "rejected":
                badge = "rejected"
                badge_label = "Rejected"

            owner_label = "Individual Owner"
            if a["owner_type"] == "legal_entity" and a.get("legal_entity_name"):
                owner_label = f"Legal Entity: {a['legal_entity_name']}"

            registry.append({
                "agent_id": a["agent_id"],
                "agent_name": a["agent_name"],
                "description": a.get("agent_description") or "",
                "endpoint": a.get("agent_endpoint") or "",
                "capabilities": a.get("agent_capabilities") or [],
                "owner_label": owner_label,
                "owner_type": a["owner_type"],
                "verification_badge": badge,
                "verification_label": badge_label,
                "verification_date": a.get("verification_date"),
                "ca_certificate_id": a.get("ca_certificate_id"),
                "submitted_at": a.get("submitted_at"),
                "telegram_bot_username": a.get("telegram_bot_username"),
                "website_url": a.get("website_url"),
                "country": a.get("country"),
            })
        return registry
