package handlers

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"path/filepath"
	"strings"
	"time"

	"aggios-app/backend/internal/api/middleware"

	"github.com/google/uuid"
	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
)

// UploadLogo handles logo file uploads
func (h *AgencyHandler) UploadLogo(w http.ResponseWriter, r *http.Request) {
	// Only accept POST
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	log.Printf("Logo upload request received from tenant")

	// Get tenant ID from context
	tenantIDVal := r.Context().Value(middleware.TenantIDKey)
	if tenantIDVal == nil {
		log.Printf("No tenant ID in context")
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}

	// Try to get as uuid.UUID first, if that fails try string and parse
	var tenantID uuid.UUID
	var ok bool
	
	tenantID, ok = tenantIDVal.(uuid.UUID)
	if !ok {
		// Try as string
		tenantIDStr, isString := tenantIDVal.(string)
		if !isString {
			log.Printf("Invalid tenant ID type: %T", tenantIDVal)
			http.Error(w, "Invalid tenant ID", http.StatusBadRequest)
			return
		}
		
		var err error
		tenantID, err = uuid.Parse(tenantIDStr)
		if err != nil {
			log.Printf("Failed to parse tenant ID: %v", err)
			http.Error(w, "Invalid tenant ID format", http.StatusBadRequest)
			return
		}
	}

	log.Printf("Processing logo upload for tenant: %s", tenantID)

	// Parse multipart form (2MB max)
	const maxLogoSize = 2 * 1024 * 1024
	if err := r.ParseMultipartForm(maxLogoSize); err != nil {
		http.Error(w, "File too large", http.StatusBadRequest)
		return
	}

	file, header, err := r.FormFile("logo")
	if err != nil {
		http.Error(w, "Failed to read file", http.StatusBadRequest)
		return
	}
	defer file.Close()

	// Validate file type
	contentType := header.Header.Get("Content-Type")
	if contentType != "image/png" && contentType != "image/jpeg" && contentType != "image/svg+xml" && contentType != "image/jpg" {
		http.Error(w, "Only PNG, JPG or SVG files are allowed", http.StatusBadRequest)
		return
	}

	// Get logo type (logo or horizontal)
	logoType := r.FormValue("type")
	if logoType != "logo" && logoType != "horizontal" {
		logoType = "logo"
	}

	// Get current logo URL from database to delete old file
	var currentLogoURL string
	var queryErr error
	if logoType == "horizontal" {
		queryErr = h.tenantRepo.DB().QueryRow("SELECT logo_horizontal_url FROM tenants WHERE id = $1", tenantID).Scan(&currentLogoURL)
	} else {
		queryErr = h.tenantRepo.DB().QueryRow("SELECT logo_url FROM tenants WHERE id = $1", tenantID).Scan(&currentLogoURL)
	}
	if queryErr != nil && queryErr.Error() != "sql: no rows in result set" {
		log.Printf("Warning: Failed to get current logo URL: %v", queryErr)
	}

	// Initialize MinIO client
	minioClient, err := minio.New("aggios-minio:9000", &minio.Options{
		Creds:  credentials.NewStaticV4("minioadmin", "M1n10_S3cur3_P@ss_2025!", ""),
		Secure: false,
	})
	if err != nil {
		log.Printf("Failed to create MinIO client: %v", err)
		http.Error(w, "Storage service unavailable", http.StatusInternalServerError)
		return
	}

	// Ensure bucket exists
	bucketName := "aggios-logos"
	ctx := context.Background()
	exists, err := minioClient.BucketExists(ctx, bucketName)
	if err != nil {
		log.Printf("Failed to check bucket: %v", err)
		http.Error(w, "Storage error", http.StatusInternalServerError)
		return
	}

	if !exists {
		err = minioClient.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{})
		if err != nil {
			log.Printf("Failed to create bucket: %v", err)
			http.Error(w, "Storage error", http.StatusInternalServerError)
			return
		}
		// Set bucket policy to public-read
		policy := fmt.Sprintf(`{
			"Version": "2012-10-17",
			"Statement": [{
				"Effect": "Allow",
				"Principal": {"AWS": ["*"]},
				"Action": ["s3:GetObject"],
				"Resource": ["arn:aws:s3:::%s/*"]
			}]
		}`, bucketName)
		err = minioClient.SetBucketPolicy(ctx, bucketName, policy)
		if err != nil {
			log.Printf("Warning: Failed to set bucket policy: %v", err)
		}
	}

	// Read file content
	fileBytes, err := io.ReadAll(file)
	if err != nil {
		http.Error(w, "Failed to read file", http.StatusInternalServerError)
		return
	}

	// Generate unique filename
	ext := filepath.Ext(header.Filename)
	filename := fmt.Sprintf("tenants/%s/%s-%d%s", tenantID, logoType, time.Now().Unix(), ext)

	// Upload to MinIO
	_, err = minioClient.PutObject(
		ctx,
		bucketName,
		filename,
		bytes.NewReader(fileBytes),
		int64(len(fileBytes)),
		minio.PutObjectOptions{
			ContentType: contentType,
		},
	)
	if err != nil {
		log.Printf("Failed to upload to MinIO: %v", err)
		http.Error(w, "Failed to save file", http.StatusInternalServerError)
		return
	}

	// Generate public URL through API (not direct MinIO access)
	// This is more secure and doesn't require DNS configuration
	logoURL := fmt.Sprintf("http://api.localhost/api/files/%s/%s", bucketName, filename)
	
	log.Printf("Logo uploaded successfully: %s", logoURL)

	// Delete old logo file from MinIO if exists
	if currentLogoURL != "" && currentLogoURL != "https://via.placeholder.com/150" {
		// Extract object key from URL
		// Example: http://api.localhost/api/files/aggios-logos/tenants/uuid/logo-123.png -> tenants/uuid/logo-123.png
		oldFilename := ""
		if len(currentLogoURL) > 0 {
			// Split by /api/files/{bucket}/ to get the file path
			apiPrefix := fmt.Sprintf("http://api.localhost/api/files/%s/", bucketName)
			if strings.HasPrefix(currentLogoURL, apiPrefix) {
				oldFilename = strings.TrimPrefix(currentLogoURL, apiPrefix)
			} else {
				// Fallback for old MinIO URLs
				baseURL := fmt.Sprintf("%s/%s/", h.config.Minio.PublicURL, bucketName)
				if len(currentLogoURL) > len(baseURL) {
					oldFilename = currentLogoURL[len(baseURL):]
				}
			}
		}
		
		if oldFilename != "" {
			err = minioClient.RemoveObject(ctx, bucketName, oldFilename, minio.RemoveObjectOptions{})
			if err != nil {
				log.Printf("Warning: Failed to delete old logo %s: %v", oldFilename, err)
				// Don't fail the request if deletion fails
			} else {
				log.Printf("Old logo deleted successfully: %s", oldFilename)
			}
		}
	}

	// Update tenant record in database
	var err2 error
	log.Printf("Updating database: tenant_id=%s, logo_type=%s, logo_url=%s", tenantID, logoType, logoURL)
	
	if logoType == "horizontal" {
		_, err2 = h.tenantRepo.DB().Exec("UPDATE tenants SET logo_horizontal_url = $1, updated_at = NOW() WHERE id = $2", logoURL, tenantID)
	} else {
		_, err2 = h.tenantRepo.DB().Exec("UPDATE tenants SET logo_url = $1, updated_at = NOW() WHERE id = $2", logoURL, tenantID)
	}

	if err2 != nil {
		log.Printf("ERROR: Failed to update logo in database: %v", err2)
		http.Error(w, fmt.Sprintf("Failed to update database: %v", err2), http.StatusInternalServerError)
		return
	}
	
	log.Printf("SUCCESS: Logo saved to database successfully!")

	// Return success response
	response := map[string]string{
		"logo_url": logoURL,
		"message":  "Logo uploaded successfully",
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}
