package csvimporter

import (
	"context"
	"fmt"
	"strconv"

	"catalogue.midpdsa.com/src/db/catalogue"
	"github.com/jackc/pgx/v5/pgtype"
)

func (imp *Importer) ImportGRCShocks(filename string) (ImportResult, error) {
	return imp.importGRCShocks(filename, "Ligero")
}

func (imp *Importer) ImportGRCShocksHeavy(filename string) (ImportResult, error) {
	return imp.importGRCShocks(filename, "Pesado")
}

func (imp *Importer) importGRCShocks(filename, vehicleType string) (ImportResult, error) {
	result := ImportResult{Table: "grc_shock_brand_specs"}

	records, err := imp.readCSVSeparator(filename, '|')
	if err != nil {
		return result, fmt.Errorf("failed to read CSV: %w", err)
	}

	if len(records) < 2 {
		return result, fmt.Errorf("no data rows in CSV")
	}

	ctx := context.Background()

	vehicleTypeID, err := imp.findOrCreateVehicleType(ctx, vehicleType)
	if err != nil {
		return result, fmt.Errorf("failed to get vehicle type: %w", err)
	}

	shockBrandID, err := imp.findOrCreateShockBrand(ctx, "GRC")
	if err != nil {
		return result, fmt.Errorf("failed to get shock brand: %w", err)
	}

	headerMap := make(map[string]int)
	for idx, col := range records[0] {
		normalized := normalizeHeaderKey(col)
		headerMap[normalized] = idx
	}

	dataRows := records[1:]

	var errorRows []ErrorRow
	err = imp.processGRCShocksRecursive(ctx, dataRows, headerMap, vehicleTypeID, shockBrandID, &result, &errorRows, 0)
	if err != nil {
		return result, err
	}

	if len(errorRows) > 0 {
		err = imp.writeErrorCSV("grc_shocks_errors.csv", records[0], errorRows)
		if err != nil {
			fmt.Printf("  Warning: failed to write error CSV: %v\n", err)
		}
	}

	return result, nil
}

func (imp *Importer) processGRCShocksRecursive(ctx context.Context, rows [][]string, headerMap map[string]int, vehicleTypeID, shockBrandID int32, result *ImportResult, errorRows *[]ErrorRow, startIdx int) error {
	if startIdx >= len(rows) {
		return nil
	}

	endIdx := startIdx + batchSize
	if endIdx > len(rows) {
		endIdx = len(rows)
	}

	for i := startIdx; i < endIdx; i++ {
		row := rows[i]
		rowNum := i + 2

		marca := getColumnValue(row, headerMap, "marca")
		modelo := getColumnValue(row, headerMap, "modelo")
		ano := getColumnValue(row, headerMap, "ano")
		numeroDeParte := getColumnValue(row, headerMap, "numerodeparte")
		producto := getColumnValue(row, headerMap, "producto")
		serie := getColumnValue(row, headerMap, "serie")
		tier := getColumnValue(row, headerMap, "tier")
		cantidad := getColumnValue(row, headerMap, "cantidad")
		posicion := getColumnValue(row, headerMap, "posicion")
		accesorios := getColumnValue(row, headerMap, "accesorios")
		longitudExtendida := getColumnValue(row, headerMap, "longitudextendida")
		longitudComprimida := getColumnValue(row, headerMap, "longitudcomprimida")
		carrera := getColumnValue(row, headerMap, "carrera")
		montajeSuperior := getColumnValue(row, headerMap, "montajesuperior")
		montajeInferior := getColumnValue(row, headerMap, "montajeinferior")
		imagen := getColumnValue(row, headerMap, "imagen")
		atributos := getColumnValue(row, headerMap, "atributosvehiculo")
		notas := getColumnValue(row, headerMap, "notasaplicacion")

		if numeroDeParte == "" || numeroDeParte == "MISSING" {
			result.Errors++
			*errorRows = append(*errorRows, ErrorRow{Row: row, Error: "Missing part number", RowNum: rowNum})
			continue
		}

		if marca == "" || marca == "MISSING" || modelo == "" || modelo == "MISSING" {
			result.Errors++
			*errorRows = append(*errorRows, ErrorRow{Row: row, Error: "Missing marca or modelo", RowNum: rowNum})
			continue
		}

		modelYearID, err := imp.findOrCreateVehicleModelYear(ctx, marca, modelo, vehicleTypeID)
		if err != nil {
			result.Errors++
			*errorRows = append(*errorRows, ErrorRow{Row: row, Error: fmt.Sprintf("Failed to find/create vehicle model year: %v", err), RowNum: rowNum})
			continue
		}

		position := imp.parsePosition(posicion)
		qty := 1
		if cantidad != "" {
			if _, err := fmt.Sscanf(cantidad, "%d", &qty); err != nil {
				qty = 1
			}
		}

		extLong := parseInt(longitudExtendida)
		compLong := parseInt(longitudComprimida)
		ext := parseInt(carrera)

		if err := imp.insertShockBrandSpec(ctx, catalogue.CreateShockBrandSpecParams{
			PartNumber:           pgtype.Text{String: numeroDeParte, Valid: true},
			Product:              pgtype.Text{String: producto, Valid: producto != "" && producto != "MISSING"},
			Serie:                pgtype.Text{String: serie, Valid: serie != "" && serie != "MISSING"},
			Quantity:             pgtype.Int2{Int16: int16(qty), Valid: true},
			Tier:                 pgtype.Text{String: tier, Valid: tier != "" && tier != "MISSING"},
			Position:             pgtype.Text{String: position, Valid: position != ""},
			Accesories:           pgtype.Text{String: accesorios, Valid: accesorios != "" && accesorios != "MISSING"},
			ExtendedLong:         pgtype.Int4{Int32: extLong, Valid: extLong > 0},
			CompressedLong:       pgtype.Int4{Int32: compLong, Valid: compLong > 0},
			Extension:            pgtype.Int4{Int32: ext, Valid: ext > 0},
			SuperiorMount:        pgtype.Text{String: montajeSuperior, Valid: montajeSuperior != "" && montajeSuperior != "MISSING"},
			InferiorMount:        pgtype.Text{String: montajeInferior, Valid: montajeInferior != "" && montajeInferior != "MISSING"},
			ImageProduct:         pgtype.Text{String: imagen, Valid: imagen != "" && imagen != "MISSING"},
			VehicleAttrs:         pgtype.Text{String: atributos, Valid: atributos != "" && atributos != "MISSING"},
			Notes:                pgtype.Text{String: notas, Valid: notas != "" && notas != "MISSING"},
			FkIdVehicleModelYear: pgtype.Int4{Int32: modelYearID, Valid: true},
			FkIdShockBrand:       pgtype.Int4{Int32: shockBrandID, Valid: true},
			Years:                pgtype.Text{String: ano, Valid: ano != "" && ano != "MISSING"},
			YearsRange:           pgtype.Text{Valid: false},
		}, result); err != nil {
			result.Errors++
			*errorRows = append(*errorRows, ErrorRow{Row: row, Error: fmt.Sprintf("Database insert failed: %v", err), RowNum: rowNum})
			continue
		}
	}

	fmt.Printf("  GRC Shocks: %d rows processed (total inserted: %d, errors: %d)\n", endIdx, result.Inserted, result.Errors)

	return imp.processGRCShocksRecursive(ctx, rows, headerMap, vehicleTypeID, shockBrandID, result, errorRows, endIdx)
}

func parseInt(s string) int32 {
	if s == "" {
		return 0
	}
	if f, err := strconv.ParseFloat(s, 64); err == nil {
		return int32(f + 0.5)
	}
	n, err := strconv.Atoi(s)
	if err != nil {
		return 0
	}
	return int32(n)
}
