package encounter

import (
	"context"
	"fmt"

	"service/internal/infrastructure/database"
	"service/pkg/utils/query"
)

// Repository mendefinisikan kontrak akses database untuk worker encounter
type Repository interface {
	GetNextPendaftaran(ctx context.Context, lastID int64) (*PendaftaranDB, error)
	SaveSatuSehatID(ctx context.Context, idxdaftar int64, encounterID string) error
	SaveSyncLog(ctx context.Context, logData EncounterSyncLog) error
}

type repository struct {
	dbManager database.Service
}

func NewRepository(dbManager database.Service) Repository {
	return &repository{dbManager: dbManager}
}

func (r *repository) GetNextPendaftaran(ctx context.Context, lastID int64) (*PendaftaranDB, error) {
	var p PendaftaranDB

	// 1. Ambil koneksi database SQLX SIMRS (PostgreSQL)
	simrsDB, err := r.dbManager.GetSQLXDB("simrs")
	if err != nil {
		return nil, err
	}

	// Inisiasi Query Builder (Disable security check untuk penggunaan internal & static)
	qb := query.NewSQLQueryBuilder(query.DBTypePostgreSQL).SetSecurityOptions(false, 0)

	// 2. Ambil data Pendaftaran Utama dari SIMRS menggunakan Query Builder
	qSimrs := query.DynamicQuery{
		From:    "public.t_pendaftaran",
		Aliases: "p", // Alias untuk tabel pendaftaran
		Fields: []query.SelectField{
			{Expression: "p.idxdaftar"},
			{Expression: "p.nomr"},
			{Expression: "p.tglreg"},
			{Expression: "p.kddokter"},
			{Expression: "p.kdpoly"},
			{Expression: "p.kdcarabayar"},
			{Expression: "p.status"},
			{Expression: "p.batal"},
			{Expression: "p.jamreg"},
			{Expression: "p.masukpoly"},
			{Expression: "p.keluarpoly"},
			{Expression: "m.nama"},
			{Expression: "COALESCE(NULLIF(m.noktp_baru, ''), m.noktp) AS nik"},
		},
		Joins: []query.Join{
			{
				Type:  "LEFT",
				Table: "public.m_pasien",
				Alias: "m", // Alias untuk tabel master pasien
				OnConditions: query.FilterGroup{
					Filters: []query.DynamicFilter{
						// Relasi antar kolom: p.nomr = m.nomr
						query.CreateEqualFilter("p.nomr", "m.nomr"),
					},
				},
			},
		},
		Filters: []query.FilterGroup{
			{
				Filters: []query.DynamicFilter{
					query.CreateFilter("p.idxdaftar", query.OpGreaterThan, lastID),
				},
			},
		},
		Sort: []query.SortField{
			query.CreateAscSort("p.idxdaftar"),
		},
		Limit: 1,
	}

	err = qb.ExecuteQueryRow(ctx, simrsDB, qSimrs, &p)
	if err != nil {
		return nil, err
	}

	// 3. Lengkapi referensi IHS Number dari tabel master SATUDATA menggunakan Query Builder
	satuDataDB, err := r.dbManager.GetSQLXDB("satudata")
	if err != nil {
		return nil, fmt.Errorf("gagal koneksi ke database satudata: %w", err)
	}

	if p.NoMR.Valid && p.NoMR.String != "" {
		qPasien := query.DynamicQuery{
			From:    "public.data_pasien",
			Fields:  []query.SelectField{{Expression: "\"Nomor_satusehat\""}},
			Filters: []query.FilterGroup{{Filters: []query.DynamicFilter{query.CreateEqualFilter("\"Nomor_rekamedik\"", p.NoMR.String)}}},
			Limit:   1,
		}
		_ = qb.ExecuteQueryRow(ctx, satuDataDB, qPasien, &p.PatientIHS)
	}

	if p.KdDokter.Valid {
		qDokter := query.DynamicQuery{
			From: "public.data_pegawai",
			Fields: []query.SelectField{
				{Expression: "\"Kode_satusehat\"", Alias: "practitioner_ihs"},
				{Expression: "nik", Alias: "practitioner_nik"}, // Sesuaikan "nik" jika nama kolom di DB Anda menggunakan huruf besar "\"NIK\""
			},
			Filters: []query.FilterGroup{{Filters: []query.DynamicFilter{query.CreateEqualFilter("\"Kode_DPJP\"", fmt.Sprintf("%d", p.KdDokter.Int64))}}},
			Limit:   1,
		}
		_ = qb.ExecuteQueryRow(ctx, satuDataDB, qDokter, &p)
	}

	if p.KdPoly.Valid {
		qPoly := query.DynamicQuery{
			From:    "public.daftar_lokasi_ruang",
			Fields:  []query.SelectField{{Expression: "\"Kode_satusehat\""}},
			Filters: []query.FilterGroup{{Filters: []query.DynamicFilter{query.CreateEqualFilter("\"ID_ruang_simgos\"", fmt.Sprintf("%d", p.KdPoly.Int64))}}},
			Limit:   1,
		}
		_ = qb.ExecuteQueryRow(ctx, satuDataDB, qPoly, &p.LocationIHS)
	}

	return &p, nil
}

func (r *repository) SaveSatuSehatID(ctx context.Context, idxdaftar int64, encounterID string) error {
	simrsDB, err := r.dbManager.GetSQLXDB("simrs")
	if err != nil {
		return err
	}

	// Menggunakan transaksi DB
	tx, err := simrsDB.BeginTxx(ctx, nil)
	if err != nil {
		return err
	}
	defer tx.Rollback() // Otomatis rollback bila gagal (atau tidak di-commit)

	qb := query.NewSQLQueryBuilder(query.DBTypePostgreSQL).SetSecurityOptions(false, 0)

	updateData := query.UpdateData{
		Columns: []string{"status_bridging"},
		Values:  []interface{}{encounterID},
	}

	filters := []query.FilterGroup{
		query.CreateAndFilterGroup([]query.DynamicFilter{query.CreateEqualFilter("idxdaftar", idxdaftar)}),
	}

	// Eksekusi Update via Query Builder (melempar tx, bukan db, agar terbawa ke transaksi)
	_, err = qb.ExecuteUpdate(ctx, tx, "public.t_pendaftaran", updateData, filters)
	if err != nil {
		return err
	}

	// Terapkan data
	return tx.Commit()
}

// SaveSyncLog menyimpan histori pengiriman (Request & Response) ke tabel log
func (r *repository) SaveSyncLog(ctx context.Context, logData EncounterSyncLog) error {
	simrsDB, err := r.dbManager.GetSQLXDB("simrs")
	if err != nil {
		return err
	}

	qb := query.NewSQLQueryBuilder(query.DBTypePostgreSQL).SetSecurityOptions(false, 0)

	insertData := query.InsertData{
		Columns: []string{"idxdaftar", "encounter_id", "request_payload", "response_payload", "status", "error_message"},
		Values: []interface{}{
			logData.IdxDaftar, logData.EncounterID, logData.RequestPayload,
			logData.ResponsePayload, logData.Status, logData.ErrorMessage,
		},
	}

	// Menggunakan UPSERT (ON CONFLICT) agar jika kita mengirim ulang (resend), log otomatis diperbarui
	conflictCols := []string{"idxdaftar"}
	updateCols := []string{"encounter_id", "request_payload", "response_payload", "status", "error_message"}

	_, err = qb.ExecuteUpsert(ctx, simrsDB, "public.log_satusehat_encounter", insertData, conflictCols, updateCols)
	return err
}
