"""
Smart Card Command GUI

Graphical interface for sending APDU commands to smart cards and escape commands to readers.

REQUIRES: pyscard, tkinter
For detailed requirements and installation, please refer to the README.md.
WARNING: Escape commands are hardware-specific and may vary by reader model.
"""

import platform
import sys

# Import API functions
from API import list_readers, parse_command_string, connect_to_reader, send_command, disconnect_reader

try:
    from smartcard.util import toHexString
    from smartcard.scard import SCardReleaseContext
except ImportError:
    print("smartcard imports failed - pyscard may not be properly installed")
    sys.exit(1)

try:
    import tkinter as tk
    from tkinter import ttk, messagebox
    GUI_AVAILABLE = True
except ImportError:
    GUI_AVAILABLE = False
    if __name__ == "__main__":
        error_msg = "tkinter library not found!\n\n"
        system = platform.system()
        if system == "Darwin":
            error_msg += "For macOS, tkinter should be included with Python.\n"
            error_msg += "If missing, install Python from python.org or use:\n"
            error_msg += "  brew install python-tk\n"
        elif system == "Linux":
            error_msg += "For Ubuntu/Linux, install tkinter using:\n"
            error_msg += "  sudo apt-get install python3-tk\n"
        else:
            error_msg += "For Windows, tkinter should be included with Python.\n"
            error_msg += "If missing, reinstall Python and ensure 'tcl/tk and IDLE' is selected.\n"

        print(error_msg)
        if sys.stdout.isatty():
            input("Press Enter to exit...")
        sys.exit(1)


if GUI_AVAILABLE:
    class SmartCardCommandUI:
        def __init__(self, root):
            self.root = root
            self.root.title("Send Command")

            try:
                self.root.iconbitmap("ACS_Small.ico")
            except Exception:
                pass

            self.platform = platform.system()
            self.is_macos = self.platform == "Darwin"
            self.is_linux = self.platform == "Linux"

            if self.is_linux:
                self.root.geometry("900x700")
                self.root.minsize(850, 600)
            elif self.is_macos:
                self.root.geometry("850x650")
                self.root.minsize(750, 550)
            else:
                self.root.geometry("850x650")
                self.root.minsize(750, 550)


            self.check_platform_requirements()
            self.create_widgets()
            self.refresh_readers()

        def create_widgets(self):
            # Reader selection frame
            reader_frame = ttk.LabelFrame(self.root, text="Smart Card Reader", padding=10)
            reader_frame.pack(fill="x", padx=10, pady=5)

            reader_inner = ttk.Frame(reader_frame)
            reader_inner.pack(fill="x")

            ttk.Label(reader_inner, text="Select Reader:").pack(side="left", padx=5)
            self.reader_var = tk.StringVar()
            self.reader_combo = ttk.Combobox(reader_inner, textvariable=self.reader_var, state="readonly")
            self.reader_combo.pack(side="left", fill="x", expand=True, padx=5)

            self.refresh_button = ttk.Button(reader_inner, text="Refresh", command=self.refresh_readers)
            self.refresh_button.pack(side="left", padx=5)

            # Command frame (contains both APDU and Escape commands)
            command_frame = ttk.LabelFrame(self.root, text="Commands", padding=10)
            command_frame.pack(fill="x", padx=10, pady=5)

            command_frame.columnconfigure(1, weight=1)
            command_frame.columnconfigure(2, weight=0)

            # APDU Command section
            ttk.Label(command_frame, text="Enter APDU (hex):").grid(row=0, column=0, padx=5, sticky="w")

            entry_width = 40 if self.is_linux else 35
            self.apdu_entry = ttk.Entry(command_frame, width=entry_width)
            self.apdu_entry.grid(row=0, column=1, padx=5, sticky="ew")
            self.apdu_entry.insert(0, "FF CA 00 00 00")

            self.send_apdu_button = ttk.Button(command_frame, text="Send APDU", command=self.send_apdu)
            self.send_apdu_button.grid(row=0, column=2, padx=5, sticky="e")

            # Escape Command section (under APDU)
            ttk.Label(command_frame, text="Enter Escape Command (hex):").grid(row=1, column=0, padx=5, pady=(10,0), sticky="w")

            self.escape_entry = ttk.Entry(command_frame, width=entry_width)
            self.escape_entry.grid(row=1, column=1, padx=5, pady=(10,0), sticky="ew")
            self.escape_entry.insert(0, "E0 00 00 18 00")

            self.send_escape_button = ttk.Button(command_frame, text="Send Escape Command", command=self.send_escape_command)
            self.send_escape_button.grid(row=1, column=2, padx=5, pady=(10,0), sticky="e")

            # Response frame
            response_frame = ttk.LabelFrame(self.root, text="Response", padding=10)
            response_frame.pack(fill="both", expand=True, padx=10, pady=5)

            text_height = 14 if self.is_linux else 10
            self.response_text = tk.Text(response_frame, height=text_height, wrap=tk.WORD)
            self.response_text.pack(fill="both", expand=True)

        def check_platform_requirements(self):
            if self.is_linux:
                try:
                    import subprocess
                    result = subprocess.run(['systemctl', 'is-active', 'pcscd'],
                                          capture_output=True, text=True, timeout=2)
                    if result.returncode != 0:
                        messagebox.showwarning(
                            "PCSC Service",
                            "pcscd service may not be running. Please ensure it is active.\n\n"
                            "On Ubuntu/Linux, you might need to run:\n"
                            "  sudo systemctl start pcscd\n"
                            "  sudo systemctl enable pcscd\n"
                            "If not installed:\n"
                            "  sudo apt-get install pcscd libpcsclite1"
                        )
                except (FileNotFoundError, subprocess.TimeoutExpired, Exception):
                    pass

        def refresh_readers(self):
            reader_list = list_readers()
            self.reader_combo['values'] = [str(reader) for reader in reader_list]
            if len(reader_list) > 0:
                self.reader_combo.current(0)
            else:
                messagebox.showwarning("No Readers Found", "No smart card readers found! Please check connections and drivers.")


        def send_apdu(self):
            # Check if reader is selected
            if not self.reader_var.get():
                messagebox.showerror("Error", "Please select a reader first!")
                return

            command_str = self.apdu_entry.get().strip()
            if not command_str:
                error_msg = "Please enter an APDU command."
                self.update_response_text(error_msg + "\n")
                return

            # Get selected reader
            reader_list = list_readers()
            selected_reader = None
            for reader in reader_list:
                if str(reader) == self.reader_var.get():
                    selected_reader = reader
                    break

            if not selected_reader:
                messagebox.showerror("Error", "Selected reader not found!")
                return

            connection = None
            try:
                # Connect to reader in APDU mode
                connection, error_msg, _ = connect_to_reader(selected_reader)
                if not connection:
                    help_msg = error_msg or "Connection failed. Please check reader and card."
                    messagebox.showerror("Error", help_msg)
                    return

                # Send APDU command
                success, response, sw1, sw2, error_msg = send_command(
                    connection,
                    command_str,
                    mode='apdu'
                )

                if success:
                    self.update_response_text(f"Sent APDU: {toHexString(parse_command_string(command_str))}\n")
                    self.update_response_text(f"Response Data: {toHexString(response)}\n")
                    self.update_response_text(f"Status Words: {hex(sw1)[2:].zfill(2).upper()} {hex(sw2)[2:].zfill(2).upper()}\n")
                    self.update_response_text("-" * 80 + "\n")
                else:
                    self.update_response_text(f"Failed to send APDU: {error_msg}\n")
                    messagebox.showerror("Error", f"Failed to send APDU: {error_msg}")

            except ValueError as e:
                error_msg = f"Invalid APDU format: {str(e)}"
                self.update_response_text(error_msg + "\n")
                messagebox.showerror("Error", error_msg)
            except Exception as e:
                error_msg = f"Error sending APDU: {str(e)}"
                self.update_response_text(error_msg + "\n")
                messagebox.showerror("Error", error_msg)
            finally:
                # Always disconnect
                disconnect_reader(connection)

        def send_escape_command(self):
            # Check if reader is selected
            if not self.reader_var.get():
                messagebox.showerror("Error", "Please select a reader first!")
                return

            command_str = self.escape_entry.get().strip()
            if not command_str:
                error_msg = "Please enter an escape command."
                self.update_response_text(error_msg + "\n")
                return

            # Get selected reader
            reader_list = list_readers()
            selected_reader = None
            for reader in reader_list:
                if str(reader) == self.reader_var.get():
                    selected_reader = reader
                    break

            if not selected_reader:
                messagebox.showerror("Error", "Selected reader not found!")
                return

            hcard = None
            hcontext = None
            try:
                # Connect to reader in escape mode (direct connection)
                hcard, error_msg, hcontext = connect_to_reader(selected_reader, mode='direct')
                if not hcard:
                    help_msg = error_msg or "Connection failed. Please check reader."
                    messagebox.showerror("Error", help_msg)
                    return

                # Send escape command
                command_bytes = parse_command_string(command_str)
                self.update_response_text(f"Sending escape command: {toHexString(command_bytes)}\n")
                success, response, error_msg = send_command(hcard, command_bytes, mode='escape')

                if success:
                    self.update_response_text("Escape command sent successfully\n")
                    if response and len(response) > 0:
                        response_str = toHexString(response[:50]) if len(response) > 50 else toHexString(response)
                        self.update_response_text(f"Response ({len(response)} bytes): {response_str}\n")
                    else:
                        self.update_response_text("Response: (empty)\n")
                    self.update_response_text("-" * 80 + "\n")
                else:
                    self.update_response_text(f"Failed to send escape command: {error_msg}\n")
                    messagebox.showerror("Error", f"Failed to send escape command: {error_msg}")

            except ValueError as e:
                error_msg = f"Invalid escape command format: {str(e)}"
                self.update_response_text(error_msg + "\n")
                messagebox.showerror("Error", error_msg)
            except Exception as e:
                error_msg = f"Error sending escape command: {str(e)}"
                self.update_response_text(error_msg + "\n")
                messagebox.showerror("Error", error_msg)
            finally:
                disconnect_reader(hcard, hcontext)

        def update_response_text(self, message):
            self.response_text.insert(tk.END, message)
            self.response_text.see(tk.END)

        def cleanup(self):
            # No persistent connections to clean up since we connect/disconnect in each operation
            pass


if __name__ == "__main__":
    if GUI_AVAILABLE:
        root = tk.Tk()
        app = SmartCardCommandUI(root)

        def on_closing():
            app.cleanup()
            root.destroy()

        root.protocol("WM_DELETE_WINDOW", on_closing)
        root.mainloop()
    else:
        print("GUI not available. Use the API functions programmatically:")
        print("  # Import from API.py for programmatic usage")
        print("  # from API import list_readers, connect_to_reader, send_command, disconnect_card")