
# -*- coding: utf-8 -*-
"""
Tamer Serbes Capture
Python + CustomTkinter professional screenshot app.

Run:
    python main.py

Build EXE:
    python -m PyInstaller --noconfirm --clean --onefile --windowed --name "Tamer Serbes Capture" --icon ".\assets\app_icon.ico" --collect-all customtkinter --hidden-import=PIL._tkinter_finder --hidden-import=win32clipboard --hidden-import=win32con main.py
"""

import io
import os
import sys
import time
import logging
from datetime import datetime
from pathlib import Path
import tkinter as tk
from tkinter import messagebox

import customtkinter as ctk
import mss
from PIL import Image, ImageTk, ImageDraw, ImageFont, ImageOps

try:
    import win32clipboard
    import win32con
except Exception:
    win32clipboard = None
    win32con = None

try:
    import win32gui
except Exception:
    win32gui = None


APP_NAME = "Tamer Serbes Capture"
APP_VERSION = "V3.0"
PREVIOUS_VERSION = "V3.0"
COPYRIGHT_TEXT = "© 2026 Tamer Serbes Capture. Tüm hakları saklıdır."
WEBSITE = "www.tamerserbes.com"

ROOT_DIR = Path(sys.executable).resolve().parent if getattr(sys, "frozen", False) else Path(__file__).resolve().parent
ASSETS_DIR = ROOT_DIR / "assets"
SCREENSHOT_DIR = ROOT_DIR / "screenshots"
LOG_DIR = ROOT_DIR / "logs"

SCREENSHOT_DIR.mkdir(exist_ok=True)
LOG_DIR.mkdir(exist_ok=True)
ASSETS_DIR.mkdir(exist_ok=True)

logging.basicConfig(
    filename=str(LOG_DIR / "app.log"),
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s",
    encoding="utf-8",
)


def resource_path(relative_path: str) -> Path:
    """Works in normal Python and PyInstaller onefile."""
    base = getattr(sys, "_MEIPASS", str(ROOT_DIR))
    return Path(base) / relative_path



def find_asset(*names: str) -> Path | None:
    """Find an asset next to EXE/source first, then inside PyInstaller bundle."""
    for name in names:
        local_file = ASSETS_DIR / name
        if local_file.exists():
            return local_file

        bundled_file = resource_path(f"assets/{name}")
        if bundled_file.exists():
            return bundled_file

    return None


def ensure_default_assets() -> None:
    """Create only the default app icon if missing. Background/logo are user assets."""
    icon_path = ASSETS_DIR / "app_icon.ico"

    if not icon_path.exists():
        img = Image.new("RGBA", (256, 256), (7, 18, 34, 255))
        draw = ImageDraw.Draw(img)
        draw.rounded_rectangle(
            (10, 10, 246, 246),
            radius=40,
            fill=(7, 18, 34, 255),
            outline=(0, 153, 255, 255),
            width=7,
        )
        try:
            font = ImageFont.truetype("arialbd.ttf", 92)
        except Exception:
            font = ImageFont.load_default()
        logo_text = "TS"
        bbox = draw.textbbox((0, 0), logo_text, font=font)
        tw = bbox[2] - bbox[0]
        th = bbox[3] - bbox[1]
        draw.text(((256 - tw) / 2, (256 - th) / 2 - 8), logo_text, font=font, fill=(255, 255, 255, 255))
        img.save(icon_path, sizes=[(256, 256), (128, 128), (64, 64), (48, 48), (32, 32), (16, 16)])


ensure_default_assets()


class CaptureApp(ctk.CTk):
    def __init__(self) -> None:
        super().__init__()

        ctk.set_appearance_mode("dark")
        ctk.set_default_color_theme("blue")

        self.title(f"{APP_NAME} {APP_VERSION}")
        self.geometry("1536x864")
        self.minsize(1180, 720)

        self.current_format = ctk.StringVar(value="PNG")
        self.delay_seconds = ctk.IntVar(value=0)

        self.last_image_path: Path | None = None
        self.preview_image_ref = None
        self.history_image_refs = []
        self.history_rows = []
        self.history_row_by_path = {}
        self.nav_buttons = {}

        self.configure(fg_color="#05070b")

        self.build_layout()
        self.refresh_history()
        self.bind_shortcuts()
        self.set_status("Hazır - Kısayollar: F9 Full Screen, F10 Area, F11 Window, F12 Delay", "green")

    # ---------- UI ----------
    def build_layout(self) -> None:
        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(2, weight=1)

        self.build_titlebar()
        self.build_navbar()
        self.build_main_area()
        self.build_footer()

    def build_titlebar(self) -> None:
        bar = ctk.CTkFrame(
            self,
            height=76,
            fg_color="#060b14",
            corner_radius=0,
            border_width=0,
        )
        bar.grid(row=0, column=0, sticky="ew")
        bar.grid_columnconfigure(2, weight=1)

        logo_file = find_asset("logo.png", "logo.jpg", "logo.jpeg", "app_icon.ico")

        try:
            logo_img = Image.open(logo_file).convert("RGBA")
            self.logo_ctk = ctk.CTkImage(
                light_image=logo_img,
                dark_image=logo_img,
                size=(58, 58)
            )
            logo = ctk.CTkLabel(bar, image=self.logo_ctk, text="")
        except Exception:
            logo = ctk.CTkLabel(
                bar,
                text="TS",
                width=58,
                height=58,
                font=("Segoe UI", 18, "bold"),
                text_color="#ffffff",
                fg_color="#071222",
                corner_radius=14,
            )

        logo.grid(row=0, column=0, padx=(18, 12), pady=8)

        title_stack = ctk.CTkFrame(bar, fg_color="transparent")
        title_stack.grid(row=0, column=1, sticky="w")

        title = ctk.CTkLabel(
            title_stack,
            text="TAMER SERBES",
            font=("Segoe UI", 18, "bold"),
            text_color="#f7fbff",
        )
        title.pack(anchor="w")

        subtitle = ctk.CTkLabel(
            title_stack,
            text="CAPTURE",
            font=("Segoe UI", 19, "bold"),
            text_color="#208fff",
        )
        subtitle.pack(anchor="w", pady=(0, 0))

        version = ctk.CTkLabel(
            bar,
            text=APP_VERSION,
            font=("Segoe UI", 14, "bold"),
            text_color="#9fd1ff",
        )
        version.grid(row=0, column=2, padx=(16, 0), sticky="w")

        app_file = ctk.CTkLabel(
            bar,
            text="Tamer Serbes Capture.exe",
            font=("Segoe UI", 13),
            text_color="#c7d4e4",
        )
        app_file.grid(row=0, column=3, padx=22)

    def build_navbar(self) -> None:
        nav = ctk.CTkFrame(self, height=62, fg_color="#06090e", corner_radius=0)
        nav.grid(row=1, column=0, sticky="ew")
        nav.grid_columnconfigure(10, weight=1)

        items = [
            ("Yakala", "📷"),
            ("Düzenle", "✎"),
            ("Geçmiş", "▤"),
            ("Araçlar", "▣"),
            ("Görünüm", "⚙"),
            ("Yardım", "?"),
        ]

        for col, (name, icon) in enumerate(items):
            btn = ctk.CTkButton(
                nav,
                text=f"{icon}  {name}",
                width=150,
                height=46,
                fg_color="#06090e" if name != "Yakala" else "#0d3e78",
                hover_color="#0b65bd",
                text_color="#ffffff" if name != "Yakala" else "#20a8ff",
                font=("Segoe UI", 16),
                command=lambda n=name: self.nav_clicked(n),
            )
            btn.grid(row=0, column=col, padx=(20 if col == 0 else 6, 6), pady=8)
            self.nav_buttons[name] = btn

    def build_main_area(self) -> None:
        body = ctk.CTkFrame(self, fg_color="#05070b", corner_radius=0)
        body.grid(row=2, column=0, sticky="nsew")
        body.grid_columnconfigure(0, weight=0)
        body.grid_columnconfigure(1, weight=1)
        body.grid_columnconfigure(2, weight=0)
        body.grid_rowconfigure(0, weight=1)

        self.left_panel = ctk.CTkFrame(body, width=305, fg_color="#090d12", border_width=1, border_color="#1d2a36", corner_radius=8)
        self.left_panel.grid(row=0, column=0, padx=(18, 10), pady=10, sticky="ns")
        self.left_panel.grid_propagate(False)

        self.left_content = ctk.CTkScrollableFrame(
            self.left_panel,
            fg_color="transparent"
        )
        self.left_content.pack(fill="both", expand=True, padx=0, pady=0)

        self.center_panel = ctk.CTkFrame(body, fg_color="#05070b", corner_radius=0)
        self.center_panel.grid(row=0, column=1, padx=0, pady=10, sticky="nsew")
        self.center_panel.grid_rowconfigure(0, weight=1)
        self.center_panel.grid_columnconfigure(0, weight=1)

        self.right_panel = ctk.CTkFrame(body, width=395, fg_color="#090d12", border_width=1, border_color="#1d2a36", corner_radius=8)
        self.right_panel.grid(row=0, column=2, padx=(10, 18), pady=10, sticky="ns")
        self.right_panel.grid_propagate(False)

        self.build_left_panel()
        self.build_center_panel()
        self.build_right_panel()

    def build_left_panel(self) -> None:
        ctk.CTkLabel(
            self.left_content,
            text="YAKALA",
            font=("Segoe UI", 14, "bold"),
            text_color="#16a7ff",
        ).pack(anchor="w", padx=20, pady=(20, 12))

        self.big_action_button("▣", "Tam Ekran", "Tüm ekranı yakala", self.capture_fullscreen, active=True)
        self.big_action_button("□", "Alan Seç", "Yakalanacak alanı seç", self.capture_area)
        self.big_action_button("▭", "Aktif Pencere", "Aktif pencereyi yakala", self.capture_active_window)
        self.big_action_button("◷", "Gecikmeli Yakala", "Gecikmeli ekran yakala", self.capture_delay)

        divider = ctk.CTkFrame(self.left_content, height=1, fg_color="#1d2a36")
        divider.pack(fill="x", pady=18)

        ctk.CTkLabel(
            self.left_content,
            text="ARAÇLAR",
            font=("Segoe UI", 14, "bold"),
            text_color="#16a7ff",
        ).pack(anchor="w", padx=20, pady=(0, 12))

        self.big_action_button("📁", "Geçmişi Aç", "Ekran görüntüleri klasörü", self.open_folder, small=True)
        self.big_action_button("🖼", "Son Görüntü", "Son ekran görüntüsünü aç", self.open_last_image, small=True)
        self.big_action_button("📋", "Panoya Kopyala", "Son görüntüyü kopyala", self.copy_last_to_clipboard, small=True)
        self.big_action_button("🗑", "Son Görüntüyü Sil", "Son ekran görüntüsünü sil", self.delete_last_image, small=True)

    def big_action_button(self, icon: str, title: str, subtitle: str, command, active: bool = False, small: bool = False) -> None:
        """Create a large left-side action button.

        Important fix: the visual labels are placed on top of CTkButton.
        Without binding those child widgets, clicking the icon/text may not call
        the real button command. This method binds every visible child too.
        """

        def run_command(event=None):
            try:
                command()
            except Exception as error:
                logging.exception("Button action failed")
                messagebox.showerror("Hata", f"İşlem çalışmadı:\n{error}")
            return "break"

        row = ctk.CTkButton(
            self.left_content,
            text="",
            height=58 if not small else 52,
            fg_color="#0e4b91" if active else "#171b20",
            hover_color="#0d65bd",
            corner_radius=8,
            command=run_command,
        )
        row.pack(fill="x", padx=14, pady=4)

        frame = ctk.CTkFrame(row, fg_color="transparent")
        frame.place(relx=0, rely=0, relwidth=1, relheight=1)

        icon_label = ctk.CTkLabel(frame, text=icon, font=("Segoe UI", 22), text_color="#ffffff")
        icon_label.pack(side="left", padx=(18, 12))

        texts = ctk.CTkFrame(frame, fg_color="transparent")
        texts.pack(side="left", fill="both", expand=True)

        title_label = ctk.CTkLabel(texts, text=title, font=("Segoe UI", 14, "bold"), text_color="#ffffff")
        title_label.pack(anchor="w", pady=(8, 0))

        subtitle_label = ctk.CTkLabel(texts, text=subtitle, font=("Segoe UI", 11), text_color="#c7c7c7")
        subtitle_label.pack(anchor="w", pady=(2, 0))

        def bind_click(widget):
            widget.bind("<Button-1>", run_command)
            for child in widget.winfo_children():
                bind_click(child)

        bind_click(frame)

    def build_center_panel(self) -> None:
        self.bg_canvas = tk.Canvas(self.center_panel, bg="#050a14", highlightthickness=0, bd=0)
        self.bg_canvas.grid(row=0, column=0, sticky="nsew")

        # V3.0 TRUE TRANSPARENT PREVIEW:
        # Ön izleme artık CTkFrame üstünde değil, doğrudan Canvas üstüne çiziliyor.
        # Böylece siyah/koyu kutu arka planı oluşmaz.
        self.preview_canvas_image_ref = None
        self.current_preview_pil = None

        self.bg_canvas.bind("<Configure>", self.redraw_center_background)
        self.after(250, self.load_preview_placeholder)

    def redraw_center_background(self, event=None) -> None:
        self.bg_canvas.delete("all")
        w = max(1, self.bg_canvas.winfo_width())
        h = max(1, self.bg_canvas.winfo_height())

        bg_path = find_asset("background.jpg", "background.png", "background.jpeg")

        try:
            img = Image.open(bg_path).convert("RGB")
            img = ImageOps.fit(img, (w, h), method=Image.LANCZOS)

            overlay = Image.new("RGBA", (w, h), (0, 0, 0, 38))
            img = Image.alpha_composite(img.convert("RGBA"), overlay)

            self.bg_photo = ImageTk.PhotoImage(img)
            self.bg_canvas.create_image(0, 0, anchor="nw", image=self.bg_photo)
        except Exception:
            self.bg_canvas.create_rectangle(0, 0, w, h, fill="#050a14", outline="")
            self.bg_canvas.create_oval(w * .08, h * .04, w * .92, h * .80, fill="#0a223d", outline="")

        self.draw_preview_on_canvas()

    def draw_preview_on_canvas(self) -> None:
        try:
            self.bg_canvas.delete("preview_overlay")

            if self.current_preview_pil is None:
                return

            w = max(1, self.bg_canvas.winfo_width())
            h = max(1, self.bg_canvas.winfo_height())

            preview = self.current_preview_pil.copy().convert("RGBA")
            preview.thumbnail((430, 430), Image.LANCZOS)

            self.preview_canvas_image_ref = ImageTk.PhotoImage(preview)

            # Sadece şeffaf logo/halka gösterilir.
            # Yakalanan son görüntü ortada gösterilmez; sağdaki geçmiş panelinde görünür.
            self.bg_canvas.create_image(
                int(w * 0.50),
                int(h * 0.50),
                anchor="center",
                image=self.preview_canvas_image_ref,
                tags=("preview_overlay",)
            )
        except Exception:
            pass

    def build_right_panel(self) -> None:
        header = ctk.CTkFrame(self.right_panel, fg_color="transparent")
        header.pack(fill="x", padx=20, pady=(18, 8))
        header.grid_columnconfigure(0, weight=1)

        ctk.CTkLabel(header, text="GEÇMİŞ", font=("Segoe UI", 14, "bold"), text_color="#16a7ff").grid(row=0, column=0, sticky="w")
        self.history_count_label = ctk.CTkLabel(header, text="0 Görüntü", font=("Segoe UI", 11), text_color="#c9c9c9")
        self.history_count_label.grid(row=0, column=1, sticky="e")

        self.history_scroll = ctk.CTkScrollableFrame(self.right_panel, fg_color="transparent")
        self.history_scroll.pack(fill="both", expand=True, padx=12, pady=(0, 12))

    def build_footer(self) -> None:
        footer = ctk.CTkFrame(self, height=58, fg_color="#070a0f", corner_radius=0)
        footer.grid(row=3, column=0, sticky="ew")
        footer.grid_columnconfigure(1, weight=1)

        self.status_dot = ctk.CTkLabel(footer, text="●", font=("Segoe UI", 18), text_color="#28d344")
        self.status_dot.grid(row=0, column=0, padx=(25, 8), pady=16)

        self.status_label = ctk.CTkLabel(footer, text="Hazır", font=("Segoe UI", 13), text_color="#d9d9d9")
        self.status_label.grid(row=0, column=1, sticky="w")

        self.format_menu = ctk.CTkOptionMenu(
            footer,
            values=["PNG", "JPG"],
            variable=self.current_format,
            width=110,
            height=28,
        )
        self.format_menu.grid(row=0, column=2, padx=(8, 10))

        self.delay_menu = ctk.CTkOptionMenu(
            footer,
            values=["0", "3", "5"],
            command=lambda v: self.delay_seconds.set(int(v)),
            width=70,
            height=28,
        )
        self.delay_menu.set("0")
        self.delay_menu.grid(row=0, column=3, padx=(0, 12))

        ctk.CTkLabel(footer, text=APP_VERSION, font=("Segoe UI", 13), text_color="#16a7ff").grid(row=0, column=4, padx=20)
        ctk.CTkLabel(footer, text=COPYRIGHT_TEXT, font=("Segoe UI", 11), text_color="#d0d0d0").grid(row=0, column=5, padx=18)
        ctk.CTkLabel(footer, text=f"🌐  {WEBSITE}", font=("Segoe UI", 13, "bold"), text_color="#16a7ff").grid(row=0, column=6, padx=(0, 22))

    # ---------- Navigation ----------
    def nav_clicked(self, name: str) -> None:
        if name == "Yakala":
            self.set_status("Capture screen ready.", "green")
        elif name == "Geçmiş":
            self.refresh_history()
            self.set_status("History refreshed.", "green")
        elif name == "Görünüm":
            messagebox.showinfo("Görünüm", "V2.5 Logo Background: Settings bölümü yakalama motorunu bozmamak için pasif bırakıldı.")
        elif name == "Düzenle":
            messagebox.showinfo("Düzenle", "V2.5 Logo Background: Editor bölümü sonraki güvenli sürümde eklenecek.")
        elif name == "Araçlar":
            messagebox.showinfo("Araçlar", "V2.5 Logo Background: Recorder bölümü sonraki güvenli sürümde eklenecek.")
        elif name == "Yardım":
            messagebox.showinfo(
                "Yardım",
                f"{APP_NAME}\n{APP_VERSION}\n\nTam ekran, alan seçimi, geçmiş ve panoya kopyalama hazır.",
            )

    def bind_shortcuts(self) -> None:
        def safe_call(command):
            def runner(event=None):
                try:
                    command()
                except Exception as error:
                    logging.exception("Shortcut action failed")
                    messagebox.showerror("Hata", f"Kısayol çalışmadı:\n{error}")
                return "break"
            return runner

        self.bind("<F9>", safe_call(self.capture_fullscreen))
        self.bind("<F10>", safe_call(self.capture_area))
        self.bind("<F11>", safe_call(self.capture_active_window))
        self.bind("<F12>", safe_call(self.capture_delay))
        self.bind("<Control-o>", safe_call(self.open_folder))
        self.bind("<Control-O>", safe_call(self.open_folder))
        self.bind("<Control-l>", safe_call(self.open_last_image))
        self.bind("<Control-L>", safe_call(self.open_last_image))
        self.bind("<Control-H>", safe_call(self.refresh_history))
        self.bind("<Control-h>", safe_call(self.refresh_history))
        self.bind("<Control-Shift-C>", safe_call(self.copy_last_to_clipboard))
        self.bind("<Control-Shift-c>", safe_call(self.copy_last_to_clipboard))

    # ---------- Capture ----------
    def apply_delay(self) -> None:
        seconds = int(self.delay_seconds.get())
        if seconds > 0:
            self.set_status(f"{seconds} saniye bekleniyor...", "yellow")
            self.update()
            time.sleep(seconds)

    def make_file_path(self, prefix: str = "Screenshot") -> Path:
        ext = "jpg" if self.current_format.get().upper() == "JPG" else "png"
        stamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
        return SCREENSHOT_DIR / f"{prefix}_{stamp}.{ext}"

    def save_image(self, image: Image.Image, file_path: Path) -> Path:
        file_path.parent.mkdir(parents=True, exist_ok=True)
        fmt = self.current_format.get().upper()
        if fmt == "JPG":
            image.convert("RGB").save(file_path, "JPEG", quality=95)
        else:
            image.save(file_path, "PNG")
        logging.info("Saved screenshot: %s", file_path)
        self.after_capture(file_path)
        return file_path

    def capture_fullscreen(self) -> None:
        try:
            self.withdraw()
            self.update()
            self.apply_delay()
            time.sleep(0.15)

            with mss.mss() as sct:
                monitor = sct.monitors[0]
                shot = sct.grab(monitor)
                img = Image.frombytes("RGB", shot.size, shot.rgb)

            self.deiconify()
            self.lift()
            self.save_image(img, self.make_file_path())

        except Exception as error:
            self.deiconify()
            logging.exception("Full screen capture failed")
            messagebox.showerror("Hata", f"Tam ekran yakalanamadı:\n{error}")
            self.set_status("Capture failed.", "red")

    def capture_delay(self) -> None:
        if int(self.delay_seconds.get()) == 0:
            self.delay_seconds.set(3)
            self.delay_menu.set("3")
        self.capture_fullscreen()

    def capture_active_window(self) -> None:
        if win32gui is None:
            messagebox.showwarning("Eksik Modül", "Aktif pencere için pywin32 gerekir.")
            return

        try:
            self.apply_delay()
            hwnd = win32gui.GetForegroundWindow()
            rect = win32gui.GetWindowRect(hwnd)
            left, top, right, bottom = rect
            width = max(1, right - left)
            height = max(1, bottom - top)

            with mss.mss() as sct:
                shot = sct.grab({"left": left, "top": top, "width": width, "height": height})
                img = Image.frombytes("RGB", shot.size, shot.rgb)

            self.save_image(img, self.make_file_path("ActiveWindow"))

        except Exception as error:
            logging.exception("Active window capture failed")
            messagebox.showerror("Hata", f"Aktif pencere yakalanamadı:\n{error}")
            self.set_status("Active window capture failed.", "red")

    def capture_area(self) -> None:
        self.withdraw()
        self.update()
        self.apply_delay()
        time.sleep(0.15)

        try:
            with mss.mss() as sct:
                monitor = sct.monitors[1] if len(sct.monitors) > 1 else sct.monitors[0]
                shot = sct.grab(monitor)
                source_image = Image.frombytes("RGB", shot.size, shot.rgb)
        except Exception as error:
            self.deiconify()
            messagebox.showerror("Hata", f"Ekran görüntüsü alınamadı:\n{error}")
            self.set_status("Area capture failed.", "red")
            return

        overlay = tk.Toplevel(self)
        overlay.attributes("-fullscreen", True)
        overlay.attributes("-topmost", True)
        overlay.attributes("-alpha", 0.28)
        overlay.configure(bg="black")

        canvas = tk.Canvas(overlay, bg="black", highlightthickness=0, cursor="crosshair")
        canvas.pack(fill="both", expand=True)
        canvas.create_text(
            24,
            24,
            anchor="nw",
            text="Alanı seçin. İptal: ESC",
            fill="white",
            font=("Segoe UI", 20, "bold"),
        )

        state = {"x": 0, "y": 0, "rect": None}

        def cancel(_=None):
            overlay.destroy()
            self.deiconify()
            self.lift()
            self.set_status("Area selection cancelled.", "yellow")

        def down(event):
            state["x"], state["y"] = event.x, event.y
            if state["rect"]:
                canvas.delete(state["rect"])
            state["rect"] = canvas.create_rectangle(event.x, event.y, event.x, event.y, outline="#159cff", width=3)

        def move(event):
            if state["rect"]:
                canvas.coords(state["rect"], state["x"], state["y"], event.x, event.y)

        def up(event):
            x1, y1 = min(state["x"], event.x), min(state["y"], event.y)
            x2, y2 = max(state["x"], event.x), max(state["y"], event.y)

            if x2 - x1 < 12 or y2 - y1 < 12:
                cancel()
                return

            ow, oh = max(1, overlay.winfo_width()), max(1, overlay.winfo_height())
            iw, ih = source_image.size
            box = (int(x1 * iw / ow), int(y1 * ih / oh), int(x2 * iw / ow), int(y2 * ih / oh))

            try:
                cropped = source_image.crop(box)
                overlay.destroy()
                self.deiconify()
                self.lift()
                self.save_image(cropped, self.make_file_path("Area"))
            except Exception as error:
                overlay.destroy()
                self.deiconify()
                logging.exception("Area capture failed")
                messagebox.showerror("Hata", f"Alan kaydedilemedi:\n{error}")
                self.set_status("Area save failed.", "red")

        overlay.bind("<Escape>", cancel)
        canvas.bind("<ButtonPress-1>", down)
        canvas.bind("<B1-Motion>", move)
        canvas.bind("<ButtonRelease-1>", up)
        overlay.focus_force()

    # ---------- Actions ----------
    def after_capture(self, file_path: Path) -> None:
        self.last_image_path = file_path
        self.show_preview(file_path)
        self.refresh_history()
        self.set_status(f"Kaydedildi: {file_path.name}  •  görüntü sağ panelde", "green")

    def load_preview_placeholder(self) -> None:
        try:
            placeholder_path = find_asset("preview_placeholder.png")

            if placeholder_path and placeholder_path.exists():
                with Image.open(placeholder_path) as image:
                    self.current_preview_pil = image.copy().convert("RGBA")
            else:
                self.current_preview_pil = None

            self.draw_preview_on_canvas()

        except Exception:
            self.current_preview_pil = None
            self.draw_preview_on_canvas()

    def show_preview(self, file_path: Path) -> None:
        try:
            # V3.0 NO CENTER PREVIEW:
            # Son yakalanan/seçilen görüntü orta alanda gösterilmez.
            # Görüntüler sağdaki GEÇMİŞ panelinde görünür; orta alanda sadece şeffaf marka logosu kalır.
            self.load_preview_placeholder()
        except Exception:
            pass

    def refresh_history(self) -> None:
        for child in self.history_scroll.winfo_children():
            child.destroy()

        self.history_image_refs.clear()
        self.history_rows.clear()
        self.history_row_by_path.clear()

        files = []
        for p in SCREENSHOT_DIR.glob("*"):
            if p.suffix.lower() in [".png", ".jpg", ".jpeg"]:
                files.append(p)

        files.sort(key=lambda p: p.stat().st_mtime, reverse=True)

        self.history_count_label.configure(text=f"{len(files)} Görüntü")

        if not files:
            empty = ctk.CTkLabel(
                self.history_scroll,
                text="Henüz görüntü yok\n\nFull Screen ile ekran resmi alın.",
                font=("Segoe UI", 13),
                text_color="#8c9aaa",
                justify="center"
            )
            empty.pack(fill="both", expand=True, padx=20, pady=40)
            return

        for p in files[:60]:
            self.add_history_item(p)

    def add_history_item(self, path: Path) -> None:
        row = ctk.CTkFrame(
            self.history_scroll,
            fg_color="#0b0f15",
            border_width=1,
            border_color="#152535",
            corner_radius=10
        )
        row.pack(fill="x", padx=5, pady=6)

        self.history_rows.append(row)
        self.history_row_by_path[str(path)] = row

        width = 0
        height = 0
        thumb_ref = None

        try:
            with Image.open(path) as img:
                width, height = img.size
                thumb = img.copy()
                thumb.thumbnail((112, 72))

            thumb_ref = ImageTk.PhotoImage(thumb)

        except Exception:
            thumb_ref = None

        thumb_box = ctk.CTkFrame(
            row,
            width=118,
            height=78,
            fg_color="#05070b",
            border_width=1,
            border_color="#263647",
            corner_radius=8
        )
        thumb_box.pack(side="left", padx=8, pady=8)
        thumb_box.pack_propagate(False)

        if thumb_ref:
            self.history_image_refs.append(thumb_ref)
            img_label = ctk.CTkLabel(thumb_box, image=thumb_ref, text="")
            img_label.pack(fill="both", expand=True, padx=3, pady=3)
        else:
            img_label = ctk.CTkLabel(
                thumb_box,
                text="IMG",
                font=("Segoe UI", 11, "bold"),
                text_color="#16a7ff"
            )
            img_label.pack(fill="both", expand=True)

        meta = ctk.CTkFrame(row, fg_color="transparent")
        meta.pack(side="left", fill="both", expand=True, padx=(6, 6), pady=8)

        size_kb = path.stat().st_size / 1024
        size_text = f"{size_kb:.0f} KB" if size_kb < 1024 else f"{size_kb / 1024:.1f} MB"
        date_text = datetime.fromtimestamp(path.stat().st_mtime).strftime("%d.%m.%Y %H:%M:%S")
        resolution_text = f"{width} x {height}" if width and height else "Bilinmiyor"

        display_name = path.name
        if len(display_name) > 42:
            display_name = display_name[:20] + "..." + display_name[-17:]

        ctk.CTkLabel(
            meta,
            text=display_name,
            font=("Segoe UI", 12, "bold"),
            text_color="#ffffff",
            anchor="w"
        ).pack(anchor="w", fill="x")

        ctk.CTkLabel(
            meta,
            text=date_text,
            font=("Segoe UI", 11),
            text_color="#aeb6bf",
            anchor="w"
        ).pack(anchor="w", fill="x", pady=(3, 0))

        ctk.CTkLabel(
            meta,
            text=f"{size_text}   •   {resolution_text}",
            font=("Segoe UI", 11),
            text_color="#aeb6bf",
            anchor="w"
        ).pack(anchor="w", fill="x", pady=(3, 0))

        actions = ctk.CTkFrame(row, fg_color="transparent", width=58)
        actions.pack(side="right", padx=(0, 8), pady=8)
        actions.pack_propagate(False)

        ctk.CTkButton(
            actions,
            text="Aç",
            width=48,
            height=24,
            font=("Segoe UI", 10, "bold"),
            command=lambda p=path: self.open_history_item(p)
        ).pack(pady=(2, 5))

        ctk.CTkButton(
            actions,
            text="Sil",
            width=48,
            height=24,
            fg_color="#3a1515",
            hover_color="#7a2020",
            font=("Segoe UI", 10, "bold"),
            command=lambda p=path: self.delete_history_item(p)
        ).pack()

        def bind_history_widget(widget):
            widget.bind("<Button-1>", lambda e, p=path, r=row: self.select_history_item(p, r))
            widget.bind("<Double-Button-1>", lambda e, p=path: self.open_history_item(p))
            widget.bind("<Button-3>", lambda e, p=path: self.delete_history_item(p))

            for child in widget.winfo_children():
                bind_history_widget(child)

        bind_history_widget(row)

    def clear_history_selection(self) -> None:
        for row in self.history_rows:
            try:
                row.configure(fg_color="#0b0f15", border_color="#152535")
            except Exception:
                pass

    def select_history_item(self, path: Path, row=None) -> None:
        self.last_image_path = path

        if row is None:
            row = self.history_row_by_path.get(str(path))

        self.clear_history_selection()

        if row is not None:
            try:
                row.configure(fg_color="#102033", border_color="#16a7ff")
            except Exception:
                pass

        self.show_preview(path)
        self.set_status(f"Selected: {path.name}", "green")

    def open_history_item(self, path: Path) -> None:
        if path and path.exists():
            self.select_history_item(path)
            os.startfile(str(path))
            self.set_status(f"Opened: {path.name}", "green")

    def delete_history_item(self, path: Path) -> None:
        if not path or not path.exists():
            return

        if not messagebox.askyesno("Sil", f"Bu görüntü silinsin mi?\n\n{path.name}"):
            return

        try:
            path.unlink()

            if self.last_image_path == path:
                self.last_image_path = None
                self.preview_image_ref = None
                self.load_preview_placeholder()

            self.refresh_history()
            self.set_status(f"Deleted: {path.name}", "yellow")

        except Exception as error:
            messagebox.showerror("Hata", f"Silinemedi:\n{error}")
            self.set_status("Delete failed.", "red")

    def open_folder(self) -> None:
        SCREENSHOT_DIR.mkdir(exist_ok=True)
        os.startfile(str(SCREENSHOT_DIR))

    def open_last_image(self) -> None:
        path = self.get_last_image()
        if path and path.exists():
            os.startfile(str(path))
        else:
            messagebox.showinfo("Bilgi", "Henüz ekran görüntüsü yok.")

    def get_last_image(self) -> Path | None:
        if self.last_image_path and self.last_image_path.exists():
            return self.last_image_path

        files = [p for p in SCREENSHOT_DIR.glob("*") if p.suffix.lower() in [".png", ".jpg", ".jpeg"]]
        files.sort(key=lambda p: p.stat().st_mtime, reverse=True)
        return files[0] if files else None

    def copy_last_to_clipboard(self) -> None:
        if win32clipboard is None or win32con is None:
            messagebox.showwarning("Eksik Modül", "Panoya kopyalama için pywin32 gerekir.")
            return

        path = self.get_last_image()
        if not path:
            messagebox.showinfo("Bilgi", "Panoya kopyalanacak görüntü yok.")
            return

        opened = False
        try:
            with Image.open(path) as img:
                img = img.convert("RGB")
                output = io.BytesIO()
                img.save(output, "BMP")
                data = output.getvalue()[14:]
                output.close()

            win32clipboard.OpenClipboard()
            opened = True
            win32clipboard.EmptyClipboard()
            win32clipboard.SetClipboardData(win32con.CF_DIB, data)
            win32clipboard.CloseClipboard()
            opened = False

            self.set_status("Copied to clipboard.", "green")
        except Exception as error:
            logging.exception("Clipboard copy failed")
            messagebox.showerror("Hata", f"Panoya kopyalanamadı:\n{error}")
            self.set_status("Clipboard copy failed.", "red")
        finally:
            if opened:
                try:
                    win32clipboard.CloseClipboard()
                except Exception:
                    pass

    def delete_last_image(self) -> None:
        path = self.get_last_image()
        if not path:
            messagebox.showinfo("Bilgi", "Silinecek görüntü yok.")
            return

        if not messagebox.askyesno("Sil", f"Bu görüntü silinsin mi?\n\n{path.name}"):
            return

        try:
            path.unlink()
            self.last_image_path = None
            self.load_preview_placeholder()
            self.refresh_history()
            self.set_status("Last image deleted.", "yellow")
        except Exception as error:
            messagebox.showerror("Hata", f"Silinemedi:\n{error}")
            self.set_status("Delete failed.", "red")

    def set_status(self, text: str, color: str = "green") -> None:
        colors = {
            "green": "#28d344",
            "red": "#ff4b4b",
            "yellow": "#ffcc00",
        }
        self.status_dot.configure(text_color=colors.get(color, "#28d344"))
        self.status_label.configure(text=text)
        self.update_idletasks()


if __name__ == "__main__":
    app = CaptureApp()
    app.mainloop()
