# Copyright (c) 2025 Patrick Motsch
# All rights reserved.

import logging
import time
import json
import requests
from typing import Dict, Any
from modules.datamodels.datamodelChat import ActionResult, ActionDocument

logger = logging.getLogger(__name__)

async def sendDraftEmail(self, parameters: Dict[str, Any]) -> ActionResult:
    operationId = None
    try:
        # Init progress logger
        workflowId = self.services.workflow.id if self.services.workflow else f"no-workflow-{int(time.time())}"
        operationId = f"outlook_send_{workflowId}_{int(time.time())}"
        
        # Start progress tracking
        parentOperationId = parameters.get('parentOperationId')
        self.services.chat.progressLogStart(
            operationId,
            "Send Draft Email",
            "Outlook Email Sending",
            f"Processing {len(parameters.get('documentList', []))} draft(s)",
            parentOperationId=parentOperationId
        )
        
        connectionReference = parameters.get("connectionReference")
        documentList = parameters.get("documentList", [])
        
        if not connectionReference:
            if operationId:
                self.services.chat.progressLogFinish(operationId, False)
            return ActionResult.isFailure(error="Connection reference is required")
        
        if not documentList:
            if operationId:
                self.services.chat.progressLogFinish(operationId, False)
            return ActionResult.isFailure(error="documentList is required and cannot be empty")
        
        # Convert single value to list if needed
        if isinstance(documentList, str):
            documentList = [documentList]
        
        # Get Microsoft connection
        self.services.chat.progressLogUpdate(operationId, 0.2, "Getting Microsoft connection")
        connection = self.connection.getMicrosoftConnection(connectionReference)
        if not connection:
            self.services.chat.progressLogFinish(operationId, False)
            return ActionResult.isFailure(error="No valid Microsoft connection found for the provided connection reference")
        
        # Check permissions
        self.services.chat.progressLogUpdate(operationId, 0.3, "Checking permissions")
        permissions_ok = await self.connection.checkPermissions(connection)
        if not permissions_ok:
            self.services.chat.progressLogFinish(operationId, False)
            return ActionResult.isFailure(error="Connection lacks necessary permissions for Outlook operations")
        
        # Read draft email JSON documents from documentList
        self.services.chat.progressLogUpdate(operationId, 0.4, "Reading draft email documents")
        draftEmails = []
        for docRef in documentList:
            try:
                # Get documents from document reference
                from modules.datamodels.datamodelDocref import DocumentReferenceList
                chatDocuments = self.services.chat.getChatDocumentsFromDocumentList(DocumentReferenceList.from_string_list([docRef]))
                if not chatDocuments:
                    logger.warning(f"No documents found for reference: {docRef}")
                    continue
                
                # Process each document in the reference
                for doc in chatDocuments:
                    try:
                        # Read file data
                        fileId = getattr(doc, 'fileId', None)
                        if not fileId:
                            logger.warning(f"Document {doc.fileName} has no fileId")
                            continue
                        
                        fileData = self.services.chat.getFileData(fileId)
                        if not fileData:
                            logger.warning(f"No file data found for document: {doc.fileName}")
                            continue
                        
                        # Parse JSON content
                        if isinstance(fileData, bytes):
                            jsonContent = fileData.decode('utf-8')
                        else:
                            jsonContent = str(fileData)
                        
                        # Parse JSON - handle ActionDocument format with validationMetadata wrapper
                        try:
                            draftEmailData = json.loads(jsonContent)
                            
                            # ActionDocument format: { "validationMetadata": {...}, "documentData": {...} }
                            # Extract documentData which contains the actual draft email data
                            if isinstance(draftEmailData, dict) and 'documentData' in draftEmailData:
                                documentDataContent = draftEmailData['documentData']
                                # documentData should be a dict (parsed from JSON by processSingleDocument)
                                if isinstance(documentDataContent, dict):
                                    draftEmailData = documentDataContent
                                elif isinstance(documentDataContent, str):
                                    # Legacy/fallback: parse if still a string
                                    draftEmailData = json.loads(documentDataContent)
                            
                            # Validate draft email structure
                            if not isinstance(draftEmailData, dict):
                                logger.warning(f"Document {doc.fileName} does not contain a valid draft email JSON object")
                                continue
                            
                            draftId = draftEmailData.get("draftId")
                            if not draftId:
                                logger.warning(f"Document {doc.fileName} does not contain 'draftId' field")
                                continue
                            
                            draftEmails.append({
                                "draftEmailJson": draftEmailData,
                                "draftId": draftId,
                                "sourceDocument": doc.fileName,
                                "sourceReference": docRef
                            })
                            
                        except json.JSONDecodeError as e:
                            logger.error(f"Failed to parse JSON from document {doc.fileName}: {str(e)}")
                            continue
                            
                    except Exception as e:
                        logger.error(f"Error processing document {doc.fileName}: {str(e)}")
                        continue
                        
            except Exception as e:
                logger.error(f"Error reading documents from reference {docRef}: {str(e)}")
                continue
        
        if not draftEmails:
            self.services.chat.progressLogFinish(operationId, False)
            return ActionResult.isFailure(error="No valid draft email JSON documents found in documentList")
        
        self.services.chat.progressLogUpdate(operationId, 0.6, f"Found {len(draftEmails)} draft email(s) to send")
        
        # Send all draft emails
        graph_url = "https://graph.microsoft.com/v1.0"
        headers = {
            "Authorization": f"Bearer {connection['accessToken']}",
            "Content-Type": "application/json"
        }
        
        sentResults = []
        failedResults = []
        
        self.services.chat.progressLogUpdate(operationId, 0.7, "Sending emails")
        for idx, draftEmail in enumerate(draftEmails):
            draftEmailJson = draftEmail["draftEmailJson"]
            draftId = draftEmail["draftId"]
            sourceDocument = draftEmail["sourceDocument"]
            
            try:
                send_url = f"{graph_url}/me/messages/{draftId}/send"
                sendResponse = requests.post(send_url, headers=headers)
                
                # Extract email details from draft JSON for confirmation
                subject = draftEmailJson.get("subject", "Unknown")
                recipients = draftEmailJson.get("recipients", [])
                cc = draftEmailJson.get("cc", [])
                bcc = draftEmailJson.get("bcc", [])
                attachmentsCount = draftEmailJson.get("attachments", 0)
                
                if sendResponse.status_code in [200, 202, 204]:
                    sentResults.append({
                        "status": "sent",
                        "message": "Email sent successfully",
                        "draftId": draftId,
                        "subject": subject,
                        "recipients": recipients,
                        "cc": cc,
                        "bcc": bcc,
                        "attachments": attachmentsCount,
                        "sentTimestamp": self.services.utils.timestampGetUtc(),
                        "sourceDocument": sourceDocument
                    })
                    logger.info(f"Email sent successfully. Draft ID: {draftId}, Subject: {subject}")
                    self.services.chat.progressLogUpdate(operationId, 0.7 + (idx + 1) * 0.2 / len(draftEmails), f"Sent {idx + 1}/{len(draftEmails)}: {subject}")
                else:
                    errorResult = {
                        "status": "error",
                        "message": "Failed to send draft email",
                        "draftId": draftId,
                        "subject": subject,
                        "recipients": recipients,
                        "sendError": {
                            "statusCode": sendResponse.status_code,
                            "response": sendResponse.text
                        },
                        "sentTimestamp": self.services.utils.timestampGetUtc(),
                        "sourceDocument": sourceDocument
                    }
                    failedResults.append(errorResult)
                    logger.error(f"Failed to send email. Draft ID: {draftId}, Status: {sendResponse.status_code}, Response: {sendResponse.text}")
                    
            except Exception as e:
                errorResult = {
                    "status": "error",
                    "message": f"Exception while sending draft email: {str(e)}",
                    "draftId": draftId,
                    "subject": draftEmailJson.get("subject", "Unknown"),
                    "recipients": draftEmailJson.get("recipients", []),
                    "exception": str(e),
                    "sentTimestamp": self.services.utils.timestampGetUtc(),
                    "sourceDocument": sourceDocument
                }
                failedResults.append(errorResult)
                logger.error(f"Error sending draft email {draftId}: {str(e)}")
        
        # Build result summary
        totalEmails = len(draftEmails)
        successfulEmails = len(sentResults)
        failedEmails = len(failedResults)
        
        resultData = {
            "totalEmails": totalEmails,
            "successfulEmails": successfulEmails,
            "failedEmails": failedEmails,
            "sentResults": sentResults,
            "failedResults": failedResults,
            "timestamp": self.services.utils.timestampGetUtc()
        }
        
        # Determine overall success status
        self.services.chat.progressLogUpdate(operationId, 0.9, f"Sent {successfulEmails}/{totalEmails} email(s)")
        if successfulEmails == 0:
            self.services.chat.progressLogFinish(operationId, False)
            validationMetadata = {
                "actionType": "outlook.sendDraftEmail",
                "connectionReference": connectionReference,
                "totalEmails": totalEmails,
                "successfulEmails": successfulEmails,
                "failedEmails": failedEmails,
                "status": "all_failed"
            }
            return ActionResult.isFailure(
                error=f"Failed to send all {totalEmails} email(s)",
                documents=[ActionDocument(
                    documentName=f"sent_mail_confirmation_{self._format_timestamp_for_filename()}.json",
                    documentData=json.dumps(resultData, indent=2),
                    mimeType="application/json",
                    validationMetadata=validationMetadata
                )]
            )
        elif failedEmails > 0:
            # Partial success
            logger.warning(f"Sent {successfulEmails} out of {totalEmails} emails. {failedEmails} failed.")
            validationMetadata = {
                "actionType": "outlook.sendDraftEmail",
                "connectionReference": connectionReference,
                "totalEmails": totalEmails,
                "successfulEmails": successfulEmails,
                "failedEmails": failedEmails,
                "status": "partial_success"
            }
            self.services.chat.progressLogFinish(operationId, True)
            return ActionResult(
                success=True,
                documents=[ActionDocument(
                    documentName=f"sent_mail_confirmation_{self._format_timestamp_for_filename()}.json",
                    documentData=json.dumps(resultData, indent=2),
                    mimeType="application/json",
                    validationMetadata=validationMetadata
                )]
            )
        else:
            # All successful
            logger.info(f"Successfully sent all {totalEmails} email(s)")
            validationMetadata = {
                "actionType": "outlook.sendDraftEmail",
                "connectionReference": connectionReference,
                "totalEmails": totalEmails,
                "successfulEmails": successfulEmails,
                "failedEmails": failedEmails,
                "status": "all_successful"
            }
            self.services.chat.progressLogFinish(operationId, True)
            return ActionResult(
                success=True,
                documents=[ActionDocument(
                    documentName=f"sent_mail_confirmation_{self._format_timestamp_for_filename()}.json",
                    documentData=json.dumps(resultData, indent=2),
                    mimeType="application/json",
                    validationMetadata=validationMetadata
                )]
            )
        
    except ImportError:
        logger.error("requests module not available")
        return ActionResult.isFailure(error="requests module not available")
    except Exception as e:
        logger.error(f"Error in sendDraftEmail: {str(e)}")
        return ActionResult.isFailure(error=str(e))

