import os
import re
import json
import logging
from collections import defaultdict
from datetime import datetime
from typing import Dict, Any, Optional, Union, List
from urllib.parse import urljoin
from firebase.firebase import Firebase
import utility.function as func

from ..models.base_node import BaseNode
from ..models.execution_context import ExecutionContext
from ..models.execution_result import ExecutionResult
from ..integrations.http_client import HTTPClient, HTTPClientError

logger = logging.getLogger(__name__)
fb = Firebase(host=os.environ.get("FIREBASE_HOST"))

class SMS(BaseNode):
    def __init__(self, property_id: str, node_id: str, name: str, config: Dict[str, Any], database_logger=None):
        """
        Initialize API Call Node.
        
        Args:
            property_id: Property identifier for this node instance
            node_id: Unique identifier for this node instance
            name: Human-readable name for the node
            config: Node configuration containing HTTP request details
            database_logger: Optional database logger for node-level logging
        """
        super().__init__(property_id, node_id, name, config, database_logger)
        self.node_type = "sms"
        self._http_client: Optional[HTTPClient] = None
        self.base_url = "https://baseUrl"

    def _get_http_client(self) -> HTTPClient:
        """
        Get or create HTTP client instance.
        
        Returns:
            HTTPClient instance
        """
        if self._http_client is None:
            timeout = self.config.get("timeout", 3600)
            default_headers = self.config.get("default_headers", {})
            self._http_client = HTTPClient(timeout=timeout, default_headers=default_headers)
        return self._http_client
    
    def _get_content(self, content_id: str) -> List[Dict[str, Any]]:
        """
        !!! IMPORTANT !!!
        This is a placeholder method for you to replace.
        It simulates fetching message content (e.g., from Firestore, a CMS, or a database)
        using the content_id from the node's configuration.

        Args:
            content_id: The identifier for the content to retrieve.
            context: The execution context, which may be needed to access databases.

        Returns:
            A list of valid SMS message objects.
        """
        print(f"Fetching content for content_id: {content_id}")
        content = fb.db.reference().child(f"account/{self.property_id}/content/sms/{content_id}").get()
        if not content:
            raise ValueError(f"No Content {content_id} register in Database")

        if 'text' not in content:
            raise ValueError(f"No JSON object in Content {content_id}!")
        
        return content['text']
    
    def _get_tel_number(self, user_pseudo_id) -> List:
        social_id = fb.db.reference().child(f"account/{self.property_id}/profile/{user_pseudo_id}/phoneNumber_PGP").get()
        if social_id:
            grouped = []
            private_key = func.Key.load_key_from_env("private_key")
            
            for user in social_id.values():
                user_id = user['id']
                decode_id = func.Key.pgp_decrypt(user_id, private_key)
                grouped.append(decode_id)

            return {user_pseudo_id: grouped}
        return None
    
    def _execute_send_message(self, config: Dict[str, Any], channel_id:str, user_pseudo_ids_context:List) -> ExecutionResult:
        """
        Handles the specific logic for sending a LINE push message.
        """
        content_id = config.get("content_id")
        channels = config.get("channels", [])

        print(f"user_pseudo_ids_context: {user_pseudo_ids_context}")

        if not content_id:
            return ExecutionResult(success=False, data={"error": "'content_id' not provided for message type."})
        if not isinstance(channels, list) or not channels:
            return ExecutionResult(success=False, data={"error": "'channels' must be a non-empty list."})

        message_objects = self._get_content(content_id)
        if not message_objects:
            return ExecutionResult(success=False,data={
                    f"{self.node_id}": {
                        "user_pseudo_ids": [],
                        "log_result": []
                    }
                }
            )

        #Prepare to send to each channel
        http_client = self._get_http_client()
        # push_api_url = f"{self.base_url}/message/push" if len(user_pseudo_ids_context['line_uid']) <= 1 else f"{self.base_url}/message/multicast"
        push_api_url = f"{self.base_url}/sms/3/messages"
        line_uid = user_pseudo_ids_context['line_uid'][0] if len(user_pseudo_ids_context['line_uid']) <= 1 else user_pseudo_ids_context['line_uid']
        overall_success = True

        token = os.environ.get(f"LINE_{channel_id}", None)
        if not token:
            return {"channel": channel_id, "status": "skipped", "reason": "No token"}

        # 4. Prepare the API request payload and headers
        headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}