package businessapi

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"net/textproto"
	"strings"
)

// UploadMedia uploads a media file to Meta and returns the media ID.
// Useful for pre-uploading media before referencing it in a later send call.
func (c *Client) UploadMedia(ctx context.Context, data []byte, mimeType string) (string, error) {
	return c.uploadMedia(ctx, data, mimeType)
}

// uploadMedia uploads media to the Business API and returns the media ID
func (c *Client) uploadMedia(ctx context.Context, data []byte, mimeType string) (string, error) {
	url := fmt.Sprintf("https://graph.facebook.com/%s/%s/media",
		c.config.APIVersion,
		c.config.PhoneNumberID)

	// Create multipart form data
	var requestBody bytes.Buffer
	writer := multipart.NewWriter(&requestBody)

	if strings.TrimSpace(mimeType) == "" {
		mimeType = "application/octet-stream"
	}

	// Add the file with explicit MIME type so Meta does not treat it as octet-stream.
	fileHeader := make(textproto.MIMEHeader)
	fileHeader.Set("Content-Disposition", `form-data; name="file"; filename="media"`)
	fileHeader.Set("Content-Type", mimeType)

	part, err := writer.CreatePart(fileHeader)
	if err != nil {
		return "", fmt.Errorf("failed to create form file: %w", err)
	}

	if _, err := part.Write(data); err != nil {
		return "", fmt.Errorf("failed to write file data: %w", err)
	}

	// Add messaging_product field
	if err := writer.WriteField("messaging_product", "whatsapp"); err != nil {
		return "", fmt.Errorf("failed to write messaging_product field: %w", err)
	}

	// Add type field (mime type)
	if err := writer.WriteField("type", mimeType); err != nil {
		return "", fmt.Errorf("failed to write type field: %w", err)
	}

	if err := writer.Close(); err != nil {
		return "", fmt.Errorf("failed to close multipart writer: %w", err)
	}

	// Create request
	req, err := http.NewRequestWithContext(ctx, "POST", url, &requestBody)
	if err != nil {
		return "", fmt.Errorf("failed to create request: %w", err)
	}

	req.Header.Set("Authorization", "Bearer "+c.config.AccessToken)
	req.Header.Set("Content-Type", writer.FormDataContentType())

	// Send request
	resp, err := c.httpClient.Do(req)
	if err != nil {
		return "", fmt.Errorf("failed to upload media: %w", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("failed to read response: %w", err)
	}

	if resp.StatusCode != http.StatusOK {
		var errResp ErrorResponse
		if err := json.Unmarshal(body, &errResp); err == nil {
			return "", fmt.Errorf("upload error: %s (code: %d)", errResp.Error.Message, errResp.Error.Code)
		}
		return "", fmt.Errorf("upload failed with status %d: %s", resp.StatusCode, string(body))
	}

	var uploadResp MediaUploadResponse
	if err := json.Unmarshal(body, &uploadResp); err != nil {
		return "", fmt.Errorf("failed to parse upload response: %w", err)
	}

	return uploadResp.ID, nil
}

// downloadMedia downloads media from the Business API using the media ID
func (c *Client) downloadMedia(ctx context.Context, mediaID string) (data []byte, mimeType string, err error) {
	// Step 1: Get the media URL
	url := fmt.Sprintf("https://graph.facebook.com/%s/%s",
		c.config.APIVersion,
		mediaID)

	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
	if err != nil {
		return nil, "", fmt.Errorf("failed to create request: %w", err)
	}

	req.Header.Set("Authorization", "Bearer "+c.config.AccessToken)

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, "", fmt.Errorf("failed to get media URL: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		return nil, "", fmt.Errorf("failed to get media URL, status %d: %s", resp.StatusCode, string(body))
	}

	var mediaResp MediaURLResponse
	if err := json.NewDecoder(resp.Body).Decode(&mediaResp); err != nil {
		return nil, "", fmt.Errorf("failed to parse media URL response: %w", err)
	}

	// Step 2: Download from the CDN URL
	downloadReq, err := http.NewRequestWithContext(ctx, "GET", mediaResp.URL, nil)
	if err != nil {
		return nil, "", fmt.Errorf("failed to create download request: %w", err)
	}

	downloadReq.Header.Set("Authorization", "Bearer "+c.config.AccessToken)

	downloadResp, err := c.httpClient.Do(downloadReq)
	if err != nil {
		return nil, "", fmt.Errorf("failed to download media: %w", err)
	}
	defer downloadResp.Body.Close()

	if downloadResp.StatusCode != http.StatusOK {
		return nil, "", fmt.Errorf("failed to download media, status %d", downloadResp.StatusCode)
	}

	data, err = io.ReadAll(downloadResp.Body)
	if err != nil {
		return nil, "", fmt.Errorf("failed to read media data: %w", err)
	}

	mimeType = mediaResp.MimeType
	return
}
