import os

import psycopg
from psycopg import errors

# Parameter koneksi mengikuti variabel environment PG* --
# konvensi libpq yang sama dengan psql.
KONEKSI = dict(
    host=os.environ.get("PGHOST", "localhost"),
    port=os.environ.get("PGPORT", "5432"),
    user=os.environ.get("PGUSER", "postgres"),
    dbname=os.environ.get("PGDATABASE", "toko_db"),
)

with psycopg.connect(**KONEKSI) as conn:
    cur = conn.cursor()

    # INSERT pertama: sah, masih dalam transaksi yang berjalan.
    cur.execute(
        "INSERT INTO produk (id, nama, harga, stok) VALUES (%s, %s, %s, %s)",
        (90, "Docking Station USB-C", 950000, 5),
    )
    print("INSERT id=90: sukses")

    # INSERT kedua memakai id yang sama: server menolak, psycopg
    # menerjemahkan SQLSTATE 23505 menjadi errors.UniqueViolation.
    try:
        cur.execute(
            "INSERT INTO produk (id, nama, harga, stok) VALUES (%s, %s, %s, %s)",
            (90, "Docking Station USB-C", 950000, 5),
        )
    except errors.UniqueViolation as e:
        print("INSERT ulang id=90: ditolak server")
        print("  sqlstate  :", e.sqlstate)
        print("  pesan     :", e.diag.message_primary)
        print("  constraint:", e.diag.constraint_name)
        # rollback membatalkan transaksi (termasuk INSERT id=90
        # yang tadinya sukses) dan mengembalikan koneksi ke kondisi
        # sehat sehingga bisa dipakai untuk transaksi baru.
        conn.rollback()

    # Transaksi baru pada koneksi yang sama.
    cur.execute(
        "INSERT INTO produk (id, nama, harga, stok) VALUES (%s, %s, %s, %s)",
        (91, "Mouse Pad Besar", 95000, 30),
    )
    print("Setelah rollback, transaksi baru berjalan normal")

# Verifikasi: hanya baris dari transaksi kedua yang tersimpan.
with psycopg.connect(**KONEKSI) as conn:
    cur = conn.execute("SELECT id, nama FROM produk WHERE id >= 90 ORDER BY id")
    print("Baris dengan id >= 90 yang tersimpan:")
    for id_, nama in cur.fetchall():
        print(f"  {id_} {nama}")

# lookup: mencari kelas error dari kode SQLSTATE, berguna saat
# kode error baru saja diketahui dari log server.
for kode in ("23505", "23503"):
    print(f"errors.lookup({kode!r}) ->", errors.lookup(kode).__name__)
