package csvimporter

import (
	"context"
	"encoding/csv"
	"fmt"
	"os"
	"path/filepath"
	"strings"

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

type ErrorRow struct {
	Row    []string
	Error  string
	RowNum int
}

func (imp *Importer) ImportGRCBrakes(filename string) (ImportResult, error) {
	result := ImportResult{Table: "grc_brake_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, "Ligero")
	if err != nil {
		return result, fmt.Errorf("failed to get vehicle type: %w", err)
	}

	brakeBrandID, err := imp.findOrCreateBrakeBrand(ctx, "GRC")
	if err != nil {
		return result, fmt.Errorf("failed to get brake 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.processGRCBrakesRecursive(ctx, dataRows, headerMap, vehicleTypeID, brakeBrandID, &result, &errorRows, 0)
	if err != nil {
		return result, err
	}

	if len(errorRows) > 0 {
		err = imp.writeErrorCSV("grc_brakes_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) processGRCBrakesRecursive(ctx context.Context, rows [][]string, headerMap map[string]int, vehicleTypeID, brakeBrandID 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, "número de parte")
		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")
		fmsi := getColumnValue(row, headerMap, "referencia fmsi")
		incluyeHerraje := getColumnValue(row, headerMap, "incluye herraje")
		imagen := getColumnValue(row, headerMap, "imagen")
		atributos := getColumnValue(row, headerMap, "atributosdelvehiculo")

		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
			}
		}

		if err := imp.insertBrakeBrandSpec(ctx, catalogue.CreateBrakeBrandSpecParams{
			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"},
			Tier:                 pgtype.Text{String: tier, Valid: tier != "" && tier != "MISSING"},
			Quantity:             pgtype.Int4{Int32: int32(qty), Valid: true},
			Position:             pgtype.Text{String: position, Valid: position != ""},
			Fmsi:                 pgtype.Text{String: fmsi, Valid: fmsi != "" && fmsi != "MISSING"},
			IncludesHardware:     pgtype.Text{String: incluyeHerraje, Valid: incluyeHerraje != "" && incluyeHerraje != "MISSING"},
			ImageProduct:         pgtype.Text{String: imagen, Valid: imagen != "" && imagen != "MISSING"},
			VehicleAttrs:         pgtype.Text{String: atributos, Valid: atributos != "" && atributos != "MISSING"},
			FkIdVehicleModelYear: pgtype.Int4{Int32: modelYearID, Valid: true},
			FkIdBrakeBrand:       pgtype.Int4{Int32: brakeBrandID, 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 Brakes: %d rows processed (total inserted: %d, errors: %d)\n", endIdx, result.Inserted, result.Errors)

	return imp.processGRCBrakesRecursive(ctx, rows, headerMap, vehicleTypeID, brakeBrandID, result, errorRows, endIdx)
}

func (imp *Importer) writeErrorCSV(filename string, header []string, errorRows []ErrorRow) error {
	dir := "/app/docs/errors"
	err := os.MkdirAll(dir, 0755)
	if err != nil {
		return err
	}

	file, err := os.Create(filepath.Join(dir, filename))
	if err != nil {
		return err
	}
	defer file.Close()

	writer := csv.NewWriter(file)
	defer writer.Flush()

	err = writer.Write(append(header, "error"))
	if err != nil {
		return err
	}

	for _, er := range errorRows {
		err = writer.Write(append(er.Row, er.Error))
		if err != nil {
			return err
		}
	}

	return nil
}

func getColumnValue(row []string, headerMap map[string]int, key string) string {
	key = normalizeHeaderKey(key)
	idx, ok := headerMap[key]
	if !ok || idx >= len(row) {
		return "MISSING"
	}
	return strings.TrimSpace(row[idx])
}

func (imp *Importer) readCSVSeparator(filename string, comma rune) ([][]string, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	reader := csv.NewReader(file)
	reader.Comma = comma
	reader.LazyQuotes = true
	reader.FieldsPerRecord = -1

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

	return records, nil
}
