package services

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"

	"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
)

// EnviarCorreoMicrosoft manda un correo de texto plano vía Microsoft Graph
// (POST /me/sendMail) en nombre de la cuenta conectada.
func EnviarCorreoMicrosoft(conexion *models.UmindConexion, destinatario, asunto, cuerpo string) error {
	accessToken, err := DescifrarSecretoUmind(conexion.AccessTokenEnc)
	if err != nil {
		return fmt.Errorf("no se pudo descifrar el access token: %w", err)
	}

	payload := map[string]interface{}{
		"message": map[string]interface{}{
			"subject": asunto,
			"body":    map[string]string{"contentType": "Text", "content": cuerpo},
			"toRecipients": []map[string]interface{}{
				{"emailAddress": map[string]string{"address": destinatario}},
			},
		},
	}
	body, _ := json.Marshal(payload)
	req, err := http.NewRequest(http.MethodPost, "https://graph.microsoft.com/v1.0/me/sendMail", bytes.NewReader(body))
	if err != nil {
		return err
	}
	req.Header.Set("Authorization", "Bearer "+accessToken)
	req.Header.Set("Content-Type", "application/json")

	resp, err := umindOAuthHTTPClient.Do(req)
	if err != nil {
		return fmt.Errorf("no se pudo contactar Microsoft Graph: %w", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		detalle, _ := io.ReadAll(io.LimitReader(resp.Body, 2048))
		return fmt.Errorf("Microsoft Graph respondió %d: %s", resp.StatusCode, string(detalle))
	}
	return nil
}

// LeerBandejaMicrosoft busca mensajes en la bandeja vía Microsoft Graph
// ($search sobre asunto/cuerpo/remitente) y devuelve un resumen liviano.
func LeerBandejaMicrosoft(conexion *models.UmindConexion, consulta string, limite int) ([]CorreoResumen, error) {
	if limite <= 0 || limite > 10 {
		limite = 10
	}
	accessToken, err := DescifrarSecretoUmind(conexion.AccessTokenEnc)
	if err != nil {
		return nil, fmt.Errorf("no se pudo descifrar el access token: %w", err)
	}

	q := fmt.Sprintf("https://graph.microsoft.com/v1.0/me/messages?$search=%s&$top=%d&$select=from,subject,receivedDateTime,bodyPreview",
		url.QueryEscape(`"`+consulta+`"`), limite)
	req, err := http.NewRequest(http.MethodGet, q, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Authorization", "Bearer "+accessToken)
	// $search requiere este header ("eventual consistency") en Microsoft Graph.
	req.Header.Set("ConsistencyLevel", "eventual")

	resp, err := umindOAuthHTTPClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("no se pudo contactar Microsoft Graph: %w", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		detalle, _ := io.ReadAll(io.LimitReader(resp.Body, 2048))
		return nil, fmt.Errorf("Microsoft Graph respondió %d: %s", resp.StatusCode, string(detalle))
	}

	var out struct {
		Value []struct {
			From struct {
				EmailAddress struct {
					Name    string `json:"name"`
					Address string `json:"address"`
				} `json:"emailAddress"`
			} `json:"from"`
			Subject          string `json:"subject"`
			ReceivedDateTime string `json:"receivedDateTime"`
			BodyPreview      string `json:"bodyPreview"`
		} `json:"value"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&out); err != nil {
		return nil, err
	}

	resultados := make([]CorreoResumen, 0, len(out.Value))
	for _, m := range out.Value {
		resultados = append(resultados, CorreoResumen{
			De:       m.From.EmailAddress.Address,
			Asunto:   m.Subject,
			Fecha:    m.ReceivedDateTime,
			Extracto: m.BodyPreview,
		})
	}
	return resultados, nil
}
