package controllers

import (
	"encoding/csv"
	"encoding/json"
	"fmt"
	"reflect"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
)

// ExportHelper provides export utilities for CSV, JSON, etc.
type ExportHelper struct{}

// NewExportHelper creates a new ExportHelper instance
func NewExportHelper() *ExportHelper {
	return &ExportHelper{}
}

// ExportToCSV exports data to CSV format
func (eh *ExportHelper) ExportToCSV(c *gin.Context, data interface{}, filename string, headers []string) error {
	c.Header("Content-Type", "text/csv")
	c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))

	writer := csv.NewWriter(c.Writer)
	defer writer.Flush()

	// Write headers
	if err := writer.Write(headers); err != nil {
		return err
	}

	// Convert data to slice of records
	records, err := eh.convertToCSVRecords(data)
	if err != nil {
		return err
	}

	// Write records
	for _, record := range records {
		if err := writer.Write(record); err != nil {
			return err
		}
	}

	return nil
}

// ExportToJSON exports data to JSON format
func (eh *ExportHelper) ExportToJSON(c *gin.Context, data interface{}, filename string) error {
	c.Header("Content-Type", "application/json")
	c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))

	return json.NewEncoder(c.Writer).Encode(data)
}

// convertToCSVRecords converts a slice of structs to CSV records
func (eh *ExportHelper) convertToCSVRecords(data interface{}) ([][]string, error) {
	v := reflect.ValueOf(data)
	if v.Kind() != reflect.Slice {
		return nil, fmt.Errorf("data must be a slice")
	}

	records := make([][]string, 0, v.Len())

	for i := 0; i < v.Len(); i++ {
		item := v.Index(i)
		if item.Kind() == reflect.Ptr {
			item = item.Elem()
		}

		record := make([]string, 0, item.NumField())
		for j := 0; j < item.NumField(); j++ {
			field := item.Field(j)
			record = append(record, eh.formatFieldValue(field))
		}
		records = append(records, record)
	}

	return records, nil
}

// formatFieldValue formats a field value for CSV export
func (eh *ExportHelper) formatFieldValue(v reflect.Value) string {
	switch v.Kind() {
	case reflect.String:
		return v.String()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return strconv.FormatInt(v.Int(), 10)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return strconv.FormatUint(v.Uint(), 10)
	case reflect.Float32, reflect.Float64:
		return strconv.FormatFloat(v.Float(), 'f', -1, 64)
	case reflect.Bool:
		return strconv.FormatBool(v.Bool())
	case reflect.Struct:
		// Handle time.Time
		if t, ok := v.Interface().(time.Time); ok {
			return t.Format(time.RFC3339)
		}
		return fmt.Sprintf("%v", v.Interface())
	case reflect.Ptr:
		if v.IsNil() {
			return ""
		}
		return eh.formatFieldValue(v.Elem())
	default:
		return fmt.Sprintf("%v", v.Interface())
	}
}

// ImportFromCSV imports data from CSV file
func (eh *ExportHelper) ImportFromCSV(c *gin.Context, formFieldName string) ([][]string, error) {
	file, err := c.FormFile(formFieldName)
	if err != nil {
		return nil, err
	}

	f, err := file.Open()
	if err != nil {
		return nil, err
	}
	defer f.Close()

	reader := csv.NewReader(f)
	records, err := reader.ReadAll()
	if err != nil {
		return nil, err
	}

	return records, nil
}

// Global ExportHelper instance
var Exporter = NewExportHelper()
