package tools

import (
	"context"
	"database/sql"
	"fmt"
	"os"
	"time"

	"skraak/db"
	"skraak/utils"
)

// ImportAudioFilesInput defines the input parameters for the import_audio_files tool
type ImportAudioFilesInput struct {
	FolderPath string `json:"folder_path"`
	DatasetID  string `json:"dataset_id"`
	LocationID string `json:"location_id"`
	ClusterID  string `json:"cluster_id"`
	Recursive  *bool  `json:"recursive,omitempty"` // *bool because default is true; plain bool would make "not provided" indistinguishable from "false"
}

// ImportAudioFilesOutput defines the output structure for the import_audio_files tool
type ImportAudioFilesOutput struct {
	Summary ImportSummary           `json:"summary"`
	FileIDs []string                `json:"file_ids"`
	Errors  []utils.FileImportError `json:"errors,omitempty"`
}

// ImportSummary provides summary statistics for the import operation
type ImportSummary struct {
	TotalFiles     int     `json:"total_files"`
	ImportedFiles  int     `json:"imported_files"`
	SkippedFiles   int     `json:"skipped_files"` // Duplicates
	FailedFiles    int     `json:"failed_files"`
	AudioMothFiles int     `json:"audiomoth_files"`
	TotalDuration  float64 `json:"total_duration_seconds"`
	ProcessingTime string  `json:"processing_time"`
}

// ImportAudioFiles batch imports WAV files from a folder with hash-based duplicate detection
func ImportAudioFiles(
	ctx context.Context,
	input ImportAudioFilesInput,
) (ImportAudioFilesOutput, error) {
	startTime := time.Now()
	var output ImportAudioFilesOutput

	// Default recursive to true
	recursive := true
	if input.Recursive != nil {
		recursive = *input.Recursive
	}

	// Validate database hierarchy (dataset → location → cluster)
	if err := validateImportInput(input, dbPath); err != nil {
		return output, fmt.Errorf("validation failed: %w", err)
	}

	// Open database
	database, err := db.OpenWriteableDB(dbPath)
	if err != nil {
		return output, fmt.Errorf("failed to open database: %w", err)
	}
	defer database.Close()

	// Set cluster path if empty
	err = utils.EnsureClusterPath(database, input.ClusterID, input.FolderPath)
	if err != nil {
		return output, fmt.Errorf("failed to set cluster path: %w", err)
	}

	// Import the cluster (ALL THE LOGIC IS HERE)
	tx, err := db.BeginLoggedTx(ctx, database, "import_audio_files")
	if err != nil {
		return output, fmt.Errorf("failed to begin transaction: %w", err)
	}

	clusterOutput, err := utils.ImportCluster(database, tx.UnderlyingTx(), utils.ClusterImportInput{
		FolderPath: input.FolderPath,
		DatasetID:  input.DatasetID,
		LocationID: input.LocationID,
		ClusterID:  input.ClusterID,
		Recursive:  recursive,
	})
	if err != nil {
		tx.Rollback()
		return output, fmt.Errorf("cluster import failed: %w", err)
	}

	if err := tx.Commit(); err != nil {
		return output, fmt.Errorf("transaction commit failed: %w", err)
	}

	// Map to output format
	output = ImportAudioFilesOutput{
		Summary: ImportSummary{
			TotalFiles:     clusterOutput.TotalFiles,
			ImportedFiles:  clusterOutput.ImportedFiles,
			SkippedFiles:   clusterOutput.SkippedFiles,
			FailedFiles:    clusterOutput.FailedFiles,
			AudioMothFiles: clusterOutput.AudioMothFiles,
			TotalDuration:  clusterOutput.TotalDuration,
			ProcessingTime: time.Since(startTime).String(),
		},
		FileIDs: []string{}, // File IDs not tracked currently
		Errors:  clusterOutput.Errors,
	}

	return output, nil
}

// validateImportInput validates all input parameters and database relationships
func validateImportInput(input ImportAudioFilesInput, dbPath string) error {
	// Verify folder exists
	info, err := os.Stat(input.FolderPath)
	if err != nil {
		return fmt.Errorf("folder not accessible: %w", err)
	}
	if !info.IsDir() {
		return fmt.Errorf("path is not a directory: %s", input.FolderPath)
	}

	return validateHierarchyIDs(input.DatasetID, input.LocationID, input.ClusterID, dbPath)
}

// validateHierarchyIDs validates dataset/location/cluster ID formats and database relationships
func validateHierarchyIDs(datasetID, locationID, clusterID, dbPath string) error {
	// Validate ID formats first (fast fail before DB queries)
	if err := utils.ValidateShortID(datasetID, "dataset_id"); err != nil {
		return err
	}
	if err := utils.ValidateShortID(locationID, "location_id"); err != nil {
		return err
	}
	if err := utils.ValidateShortID(clusterID, "cluster_id"); err != nil {
		return err
	}

	return db.WithReadDB(dbPath, func(database *sql.DB) error {
		// Verify dataset exists, is active, and is 'structured' type
		if err := db.ValidateDatasetTypeForImport(database, datasetID); err != nil {
			return err
		}

		// Verify location exists and belongs to dataset
		if err := db.ValidateLocationBelongsToDataset(database, locationID, datasetID); err != nil {
			return err
		}

		// Verify cluster exists and belongs to location
		if err := db.ClusterBelongsToLocation(database, clusterID, locationID); err != nil {
			return err
		}

		return nil
	})
}