import tkinter as tk
from tkinter import ttk, scrolledtext, messagebox
import sqlite3
import sys
import os
import win32print

# --- KONFIGURASI DATABASE (DIPERBARUI) ---
# 1. Ambil folder tempat script ini berada
BASE_DIR = os.path.dirname(os.path.abspath(__file__))

# 2. Definisikan kemungkinan lokasi database
# Prioritas 1: Di dalam folder 'instance' (Standar Flask)
DB_PATH_INSTANCE = os.path.join(BASE_DIR, 'instance', 'oshacomp.db')
# Prioritas 2: Di folder root (sejajar dengan app.py)
DB_PATH_ROOT = os.path.join(BASE_DIR, 'oshacomp.db')

# 3. Cek mana yang ada
if os.path.exists(DB_PATH_INSTANCE):
    DB_PATH = DB_PATH_INSTANCE
else:
    # Jika di instance tidak ada, anggap ada di root (atau akan dibuat di root)
    DB_PATH = DB_PATH_ROOT

# Debugging (Opsional: print path ke console server)
print(f"Menggunakan Database di: {DB_PATH}")

class PrintDialogApp:
    def __init__(self, root, sale_id):
        self.root = root
        self.sale_id = sale_id
        self.root.title(f"Cetak Struk - Nota #{sale_id}")
        self.root.geometry("420x600")
        
        # Variabel untuk menampung teks struk final
        self.receipt_content = ""
        
        # Setup Tampilan
        self.setup_ui()
        
        # Load Data
        self.load_printers()
        # Beri jeda sedikit agar UI render dulu baru load DB
        self.root.after(100, self.load_transaction_data)

    def setup_ui(self):
        # Frame Pilihan Printer
        frame_top = ttk.LabelFrame(self.root, text="Pilih Printer", padding=10)
        frame_top.pack(fill=tk.X, padx=10, pady=5)
        
        self.combo_printer = ttk.Combobox(frame_top, state="readonly")
        self.combo_printer.pack(fill=tk.X)

        # Frame Preview
        frame_mid = ttk.LabelFrame(self.root, text="Preview Struk", padding=10)
        frame_mid.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        # Text area untuk preview
        self.txt_preview = scrolledtext.ScrolledText(frame_mid, font=("Courier New", 10), state='normal')
        self.txt_preview.pack(fill=tk.BOTH, expand=True)

        # Frame Tombol
        frame_bot = ttk.Frame(self.root, padding=10)
        frame_bot.pack(fill=tk.X, padx=10, pady=5)
        
        ttk.Button(frame_bot, text="Batal", command=self.root.destroy).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=5)
        ttk.Button(frame_bot, text="🖨️ CETAK SEKARANG", command=self.print_now).pack(side=tk.LEFT, expand=True, fill=tk.X, padx=5)

    def load_printers(self):
        """Mendeteksi printer yang terinstall di Windows"""
        try:
            # EnumPrinters level 2 memberikan nama printer lokal & jaringan
            printers_info = win32print.EnumPrinters(win32print.PRINTER_ENUM_LOCAL | win32print.PRINTER_ENUM_CONNECTIONS)
            printer_names = [p[2] for p in printers_info]
            
            self.combo_printer['values'] = printer_names
            
            # Coba cari printer yang namanya mengandung 'POS', '58', atau 'Thermal'
            default_p = next((p for p in printer_names if any(k in p.upper() for k in ['POS', '58', 'THERMAL', 'EPSON'])), None)
            
            if default_p:
                self.combo_printer.set(default_p)
            elif printer_names:
                self.combo_printer.current(0) # Pilih yang pertama jika tidak ada yang cocok
            else:
                self.combo_printer.set("Tidak ada printer terdeteksi")
                
        except Exception as e:
            self.txt_preview.insert(tk.END, f"Error Load Printer: {e}\n")

    def load_transaction_data(self):
            """Mengambil data dari SQLite dan memformat menjadi string struk"""
            conn = None
            try:
                # Cek ketersediaan file database
                if not os.path.exists(DB_PATH):
                    self.txt_preview.delete('1.0', tk.END)
                    self.txt_preview.insert(tk.END, f"CRITICAL ERROR:\nDatabase tidak ditemukan di:\n{DB_PATH}")
                    return

                conn = sqlite3.connect(DB_PATH)
                cursor = conn.cursor()
                
                # 1. Ambil Header Penjualan (Mendukung kolom pembayaran baru)
                query_header = """
                    SELECT s.nomor_nota, s.tanggal, c.nama, s.total, s.diskon, 
                        s.total_bayar, s.metode_pembayaran, s.jumlah_terima, s.kembalian
                    FROM sales s 
                    JOIN customers c ON s.customer_id = c.id 
                    WHERE s.id = ?
                """
                cursor.execute(query_header, (self.sale_id,))
                header = cursor.fetchone()
                
                if not header:
                    self.txt_preview.insert(tk.END, f"Data transaksi ID {self.sale_id} tidak ditemukan!")
                    return

                # 2. Ambil Item Penjualan (Menampilkan Satuan yang dipilih)
                query_items = """
                    SELECT p.nama_barang, si.qty, si.satuan, si.harga, si.subtotal
                    FROM sale_items si 
                    JOIN products p ON si.product_id = p.id 
                    WHERE si.sale_id = ?
                """
                cursor.execute(query_items, (self.sale_id,))
                items = cursor.fetchall()
                
                # 3. Ambil Settings Toko
                try:
                    cursor.execute("SELECT company_name, company_address, company_phone, company_wa FROM settings LIMIT 1")
                    settings = cursor.fetchone()
                    toko_nama = settings[0] if settings else "NAMA TOKO"
                    toko_alamat = settings[1] if settings else "-"
                    toko_telp = settings[2] if settings else "-"
                    toko_wa = settings[3] if settings and settings[3] else "-"
                except:
                    toko_nama, toko_alamat, toko_telp, toko_wa = "NAMA TOKO", "-", "-", "-"

                # --- FORMATTING STRUK (Lebar 32 Karakter untuk 58mm) ---
                W = 32 
                lines = []
                
                def center(txt): return str(txt).center(W)
                def row(left, right):
                    space = W - len(str(left)) - len(str(right))
                    return str(left) + (" " * max(1, space)) + str(right)

                # HEADER TOKO
                lines.append(center(toko_nama.upper()))
                lines.append(center(toko_alamat))
                lines.append(center(f"Telp: {toko_telp}"))
                if toko_wa and toko_wa != "-":
                    lines.append(center(f"WA: {toko_wa}"))
                lines.append("=" * W)
                
                # INFO NOTA
                lines.append(f"Nota : {header[0]}")
                # Format tanggal (hilangkan milidetik)
                tgl_clean = str(header[1]).split('.')[0]
                lines.append(f"Tgl  : {tgl_clean}")
                lines.append(f"Plg  : {header[2][:25]}")
                lines.append("-" * W)
                
                # LIST BARANG
                for item in items:
                    nama_brg = item[0]
                    qty = item[1]
                    satuan = item[2] # Menampilkan misal: Slop / Bungkus / Pcs
                    harga = int(item[3])
                    subtotal = int(item[4])
                    
                    # Baris 1: Nama Barang
                    lines.append(nama_brg[:W]) 
                    # Baris 2: Detail Hitungan (Qty x Harga ... Subtotal)
                    txt_qty = f" {qty} {satuan} x {harga:,}"
                    txt_sub = f"{subtotal:,}"
                    lines.append(row(txt_qty, txt_sub))
                
                lines.append("-" * W)
                
                # FOOTER PERHITUNGAN
                # Jika ada diskon, tampilkan baris diskon
                if header[4] > 0:
                    lines.append(row("Subtotal:", f"{int(header[3]):,}"))
                    lines.append(row("Diskon:", f"-{int(header[4]):,}"))
                
                lines.append(row("TOTAL :", f"{int(header[5]):,}"))
                
                # TAMPILAN BAYAR & KEMBALI
                if header[6] == 'Tunai':
                    lines.append(row("BAYAR :", f"{int(header[7]):,}"))
                    lines.append(row("KEMBALI:", f"{int(header[8]):,}"))
                else:
                    # Untuk metode Tempo atau Cicilan
                    lines.append(row("METODE :", header[6]))
                    lines.append(row("BAYAR/DP:", f"{int(header[7]):,}"))
                
                lines.append("=" * W)
                lines.append(center("TERIMA KASIH"))
                lines.append(center("Barang yang sudah dibeli"))
                lines.append(center("tidak dapat dikembalikan"))
                lines.append("\n") 

                # Simpan data ke variabel kelas untuk preview dan cetak
                self.receipt_content = "\n".join(lines)
                
                # Tampilkan di UI Preview
                self.txt_preview.delete('1.0', tk.END)
                self.txt_preview.insert(tk.END, self.receipt_content)
                
            except Exception as e:
                self.txt_preview.delete('1.0', tk.END)
                self.txt_preview.insert(tk.END, f"ERROR DATABASE:\n{str(e)}")
            finally:
                if conn: conn.close()

    def print_now(self):
            printer_name = self.combo_printer.get()
            if not printer_name or printer_name == "Tidak ada printer terdeteksi":
                messagebox.showwarning("Peringatan", "Silakan pilih printer yang valid!")
                return

            try:
                # 1. Buka Koneksi Printer
                hPrinter = win32print.OpenPrinter(printer_name)
                try:
                    # 2. Mulai Dokumen RAW
                    hJob = win32print.StartDocPrinter(hPrinter, 1, ("Struk POS", None, "RAW"))
                    try:
                        win32print.StartPagePrinter(hPrinter)
                        
                        # 3. Persiapkan Data (ESC/POS)
                        
                        # --- A. Inisialisasi Printer (ESC @) ---
                        raw_data = b'\x1B\x40' 
                        raw_data += b'\x1B\x70\x00\x32\xFA'
                        
                        # --- C. Isi Struk ---
                        # Encode teks ke CP850 (standar printer thermal)
                        raw_data += self.receipt_content.encode('cp850', errors='replace')
                        
                        # --- D. Feed & Cut Paper (GS V 0) ---
                        # Feed 3 baris dulu biar text tidak terpotong pisau
                        raw_data += b'\n\n\n\x1D\x56\x00' 
                        
                        # 4. Kirim ke Printer
                        win32print.WritePrinter(hPrinter, raw_data)
                        
                        win32print.EndPagePrinter(hPrinter)
                    finally:
                        win32print.EndDocPrinter(hPrinter)
                finally:
                    win32print.ClosePrinter(hPrinter)
                
                # Tutup aplikasi setelah sukses print
                self.root.destroy()
                
            except Exception as e:
                messagebox.showerror("Gagal Print", f"Terjadi kesalahan saat mencetak:\n{str(e)}")

if __name__ == "__main__":
    # Cek argumen CLI (dikirim dari Flask)
    if len(sys.argv) < 2:
        sale_id = "1" 
    else:
        sale_id = sys.argv[1]
        
    # Validasi sale_id harus angka
    if not sale_id.isdigit():
        print("ID Transaksi tidak valid")
        sys.exit(1)
        
    root = tk.Tk()
    app = PrintDialogApp(root, sale_id)
    
    # Biar window muncul di atas
    root.lift()
    root.attributes('-topmost',True)
    root.after_idle(root.attributes,'-topmost',False)
    
    root.mainloop()