package darwindb

import (
	"context"
	"fmt"

	pgx "github.com/jackc/pgx/v4"
	"hg.lukegb.com/lukegb/depot/go/trains/darwin"
)

// ProcessReferenceData updates the database by processing a PportReferenceData message in the given transaction.
func ProcessReferenceData(ctx context.Context, tx pgx.Tx, pprd *darwin.PushPortReferenceData, a *Affected) error {
	crsToTIPLOC := make(map[string]string)
	for _, loc := range pprd.Locations {
		if loc.CRS != nil {
			crsToTIPLOC[*loc.CRS] = loc.TIPLOC
		}
		_, err := tx.Exec(ctx, `
INSERT INTO ref_locations
(tiploc, name, crs, toc)
VALUES
($1, $2, $3, $4)
ON CONFLICT (tiploc) DO UPDATE
SET name=COALESCE(ref_locations.override_name, $2), crs=$3, toc=$4
`, loc.TIPLOC, loc.Name, loc.CRS, loc.TOC)
		if err != nil {
			return fmt.Errorf("updating location %q: %w", loc.TIPLOC, err)
		}
		a.TIPLOC(loc.TIPLOC)
	}
	for _, toc := range pprd.TOCs {
		_, err := tx.Exec(ctx, `
INSERT INTO ref_tocs
(toc, name, url)
VALUES
($1, $2, $3)
ON CONFLICT (toc) DO UPDATE
SET name=$2, url=$3
`, toc.TOC, toc.Name, toc.URL)
		if err != nil {
			return fmt.Errorf("updating TOC %q: %w", toc.TOC, err)
		}
	}
	for _, r := range pprd.LateRunningReasons {
		_, err := tx.Exec(ctx, `
INSERT INTO ref_late_running_reasons
(code, text)
VALUES
($1, $2)
ON CONFLICT (code) DO UPDATE
SET text=$2
`, r.Code, r.Text)
		if err != nil {
			return fmt.Errorf("updating LateRunningReason %q: %w", r.Code, err)
		}
	}
	for _, r := range pprd.CancellationReasons {
		_, err := tx.Exec(ctx, `
INSERT INTO ref_cancel_reasons
(code, text)
VALUES
($1, $2)
ON CONFLICT (code) DO UPDATE
SET text=$2
`, r.Code, r.Text)
		if err != nil {
			return fmt.Errorf("updating CancellationReason %q: %w", r.Code, err)
		}
	}
	for _, v := range pprd.Via {
		_, err := tx.Exec(ctx, `
INSERT INTO ref_via
(at_crs, dest_tiploc, loc1_tiploc, loc2_tiploc, text)
VALUES
($1, $2, $3, $4, $5)
ON CONFLICT (at_crs, dest_tiploc, loc1_tiploc, loc2_tiploc) DO UPDATE
SET text=$5
RETURNING at_crs
`, v.AtCRS, v.DestTIPLOC, v.Loc1TIPLOC, v.Loc2TIPLOC, v.Text)
		if err != nil {
			return fmt.Errorf("updating Via %v/%v/%v/%v: %w", v.AtCRS, v.DestTIPLOC, v.Loc1TIPLOC, v.Loc2TIPLOC, err)
		}
		tiploc, ok := crsToTIPLOC[v.AtCRS]
		if ok {
			a.TIPLOC(tiploc)
		}
	}
	for _, cis := range pprd.CISSource {
		_, err := tx.Exec(ctx, `
INSERT INTO ref_cis
(code, name)
VALUES
($1, $2)
ON CONFLICT (code) DO UPDATE
SET name=$2
`, cis.CISCode, cis.Name)
		if err != nil {
			return fmt.Errorf("updating CISSource %v: %w", cis.CISCode, err)
		}
	}

	return nil
}