package api

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"

	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"

	"github.com/titansys/appy-builder/internal/keystore"
	"github.com/titansys/appy-builder/internal/models"
	"github.com/titansys/appy-builder/internal/queue"
)

// handleRoot returns version info or redirects to CodeCanyon in hosted mode
func (s *Server) handleRoot(c *gin.Context) {
	if s.config.Hosted {
		c.Redirect(http.StatusFound, "https://codecanyon.net/item/appy-aipowered-mobile-app-builder/61385530")
		return
	}
	c.JSON(http.StatusOK, gin.H{"version": s.version})
}

// handleTrigger is called by Appy server to trigger build processing
func (s *Server) handleTrigger(c *gin.Context) {
	s.logger.WithFields(logrus.Fields{
		"endpoint": "/trigger",
		"method":   "POST",
	}).Info("Received trigger request from Appy server")

	var err error

	if s.config.Hosted {
		// Parse site_url from request body
		var req models.TriggerRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			s.logger.WithError(err).Warn("Invalid trigger request - site_url required")
			c.JSON(http.StatusBadRequest, gin.H{
				"status":  http.StatusBadRequest,
				"message": "site_url is required in request body",
				"data":    false,
			})
			return
		}

		// Get purchase code from context (set by auth middleware)
		purchaseCode := c.GetString("purchase_code")

		s.logger.WithFields(logrus.Fields{
			"site_url": req.SiteURL,
		}).Info("Fetching builds from Appy instance")

		err = s.processor.FetchAndQueueBuildsDynamic(req.SiteURL, purchaseCode)
	} else {
		// Use config values
		err = s.processor.FetchAndQueueBuilds()
	}

	if err != nil {
		s.logger.WithError(err).Error("Failed to fetch pending builds")
		c.JSON(http.StatusInternalServerError, gin.H{
			"status":  http.StatusInternalServerError,
			"message": "Failed to fetch pending builds",
			"data":    false,
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"status":  http.StatusOK,
		"message": "Build processing triggered",
		"data": gin.H{
			"pending":    s.processor.PendingCount(),
			"processing": s.processor.ProcessingCount(),
		},
	})
}

// handleQueue returns the current queue count (called by Laravel for load balancing)
func (s *Server) handleQueue(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"status":  http.StatusOK,
		"message": "Queue status",
		"data": gin.H{
			"count":      s.processor.PendingCount(),
			"processing": s.processor.ProcessingCount(),
		},
	})
}

// handleDownload streams the built APK or AAB file to Laravel
func (s *Server) handleDownload(c *gin.Context) {
	buildID := c.Param("build_id")

	// Get purchase code from context (set by auth middleware in hosted mode)
	// In non-hosted mode, this will be empty string, so composite key = buildID
	purchaseCode := c.GetString("purchase_code")

	// Use composite key to find the correct artifact for this tenant
	compositeKey := queue.BuildCompositeKey(purchaseCode, buildID)

	s.logger.WithFields(logrus.Fields{
		"build_id":      buildID,
		"composite_key": compositeKey,
		"endpoint":      "/download",
	}).Info("Artifact download request received")

	// Check for APK file first, then AAB (using composite key)
	artifactPath := filepath.Join("./storage/builds", fmt.Sprintf("%s.apk", compositeKey))
	fileExt := ".apk"
	contentType := "application/vnd.android.package-archive"

	if _, err := os.Stat(artifactPath); err != nil {
		// APK not found, check for AAB
		artifactPath = filepath.Join("./storage/builds", fmt.Sprintf("%s.aab", compositeKey))
		fileExt = ".aab"
		contentType = "application/octet-stream"

		if _, err := os.Stat(artifactPath); err != nil {
			// Neither APK nor AAB found
			s.logger.WithFields(logrus.Fields{
				"build_id":      buildID,
				"composite_key": compositeKey,
			}).Warn("Artifact not found (checked both .apk and .aab)")
			c.JSON(http.StatusNotFound, gin.H{
				"status":  http.StatusNotFound,
				"message": "Artifact not found",
				"data":    false,
			})
			return
		}
	}

	// Get file info
	fileInfo, err := os.Stat(artifactPath)
	if err != nil {
		s.logger.WithError(err).WithFields(logrus.Fields{
			"build_id": buildID,
		}).Error("Failed to stat artifact file")
		c.JSON(http.StatusInternalServerError, gin.H{
			"status":  http.StatusInternalServerError,
			"message": "Failed to stat artifact file",
			"data":    false,
		})
		return
	}

	// Open file
	file, err := os.Open(artifactPath)
	if err != nil {
		s.logger.WithError(err).WithFields(logrus.Fields{
			"build_id": buildID,
		}).Error("Failed to open artifact file")
		c.JSON(http.StatusInternalServerError, gin.H{
			"status":  http.StatusInternalServerError,
			"message": "Failed to open artifact file",
			"data":    false,
		})
		return
	}
	defer file.Close()

	// Set headers for download
	c.Header("Content-Type", contentType)
	c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s%s", buildID, fileExt))
	c.Header("Content-Length", fmt.Sprintf("%d", fileInfo.Size()))

	// Stream file to client
	written, err := io.Copy(c.Writer, file)
	if err != nil {
		s.logger.WithError(err).WithFields(logrus.Fields{
			"build_id": buildID,
		}).Error("Failed to stream artifact")
		return
	}

	s.logger.WithFields(logrus.Fields{
		"build_id":      buildID,
		"artifact_size": written,
		"format":        fileExt,
	}).Info("Artifact streamed successfully")

	// NOTE: Artifact is NOT deleted immediately to allow Laravel to retry on failure
	// Artifacts will be cleaned up by periodic cleanup job or manual deletion
	// This prevents 404 errors when Laravel retries due to QR/Appetize failures
	file.Close()

	s.logger.WithFields(logrus.Fields{
		"build_id": buildID,
	}).Debug("Artifact kept for potential retries - cleanup handled separately")
}

// handleGenerateKeystore generates a new Android keystore
func (s *Server) handleGenerateKeystore(c *gin.Context) {
	s.logger.WithFields(logrus.Fields{
		"endpoint": "/keystores/generate",
		"method":   "POST",
	}).Info("Keystore generation request received")

	var req keystore.GenerateRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		s.logger.WithError(err).Warn("Invalid keystore generation request")
		c.JSON(http.StatusBadRequest, gin.H{
			"status":  http.StatusBadRequest,
			"message": "Invalid request body",
			"error":   err.Error(),
		})
		return
	}

	// Validate request
	if err := req.Validate(); err != nil {
		s.logger.WithError(err).Warn("Keystore generation validation failed")
		c.JSON(http.StatusBadRequest, gin.H{
			"status":  http.StatusBadRequest,
			"message": "Validation failed",
			"error":   err.Error(),
		})
		return
	}

	// Generate keystore
	s.logger.WithFields(logrus.Fields{
		"alias": req.Alias,
		"cn":    req.DN.CommonName,
	}).Debug("Generating keystore")

	result, err := keystore.Generate(req)
	if err != nil {
		s.logger.WithError(err).Error("Keystore generation failed")
		c.JSON(http.StatusInternalServerError, gin.H{
			"status":  http.StatusInternalServerError,
			"message": "Keystore generation failed",
			"error":   err.Error(),
		})
		return
	}

	s.logger.WithFields(logrus.Fields{
		"alias":        req.Alias,
		"sha1":         result.FingerprintSHA1,
		"sha256":       result.FingerprintSHA256,
		"keystore_len": len(result.KeystoreBase64),
	}).Info("Keystore generated successfully")

	c.JSON(http.StatusOK, gin.H{
		"status":  http.StatusOK,
		"message": "Keystore generated successfully",
		"data":    result,
	})
}
