import os
import shutil
import subprocess
import sys
import time
import tkinter as tk
from datetime import datetime
from pathlib import Path
from tkinter import filedialog, messagebox

from core.constants import DATA_DIR
from core.ui import ToolTip, create_button, create_card, show_empty


class CloudPage:
    def __init__(self, app, parent):
        self.app = app
        self.colors = app.colors
        self.frame = tk.Frame(parent, bg=self.colors["bg"])
        self.upload_base = DATA_DIR / "uploads"
        self.local_scope = self.app.current_data_scope() if hasattr(self.app, "current_data_scope") else self.app.get_app_mode()
        self.upload_dir = self._current_upload_dir()
        self.upload_dir.mkdir(parents=True, exist_ok=True)
        self._build()

    def _scope(self):
        # v2026.06.20.80: Cloud storage is locked to the active edition.
        return self.app.current_data_scope() if hasattr(self.app, "current_data_scope") else self.app.get_app_mode()

    def _current_upload_dir(self):
        return self.upload_base / self._scope()

    def _scope_label(self):
        scope = self._scope()
        return self.app.t("mode_personal") if scope == "personal" else self.app.t("mode_enterprise")

    def _switch_scope(self, mode):
        current = self._scope()
        if mode != current:
            try:
                self.app.set_status("personal_isolation_guard_title")
            except Exception:
                pass
            return
        self.local_scope = current
        self.refresh()

    def _update_scope_switch(self):
        current = self._scope()
        try:
            if hasattr(self, "scope_switch"):
                self.scope_switch.pack_forget()
        except Exception:
            pass
        for key, btn in (("personal", getattr(self, "personal_scope_btn", None)), ("enterprise", getattr(self, "enterprise_scope_btn", None))):
            if not btn:
                continue
            active = key == current
            btn.config(
                bg=self.colors["primary"] if active else self.colors["card_soft"],
                fg="white" if active else self.colors["text_secondary"],
                activebackground=self.colors["primary" if active else "primary_light"],
                activeforeground="white" if active else self.colors["primary"],
            )

    def _build(self):
        top = create_card(self.frame, self.colors, fill=tk.X, pady=(0, 10))
        bar = tk.Frame(top, bg=self.colors["card"])
        bar.pack(fill=tk.X, padx=18, pady=14)

        icon = tk.Canvas(bar, width=42, height=42, bg=self.colors["card"], highlightthickness=0)
        icon.pack(side=tk.LEFT)
        icon.create_oval(8, 15, 22, 29, fill=self.colors["primary_light"], outline=self.colors["primary"], width=2)
        icon.create_oval(17, 9, 32, 29, fill=self.colors["primary_light"], outline=self.colors["primary"], width=2)
        icon.create_rectangle(10, 22, 35, 33, fill=self.colors["primary_light"], outline=self.colors["primary"], width=2)

        title_box = tk.Frame(bar, bg=self.colors["card"])
        title_box.pack(side=tk.LEFT, padx=12)
        self.title_label = tk.Label(title_box, text=self.app.t("cloud_title"), font=("Microsoft YaHei UI", 18, "bold"), fg=self.colors["text"], bg=self.colors["card"])
        self.title_label.pack(anchor="w")
        self.subtitle_label = tk.Label(title_box, text=self.app.t("cloud_subtitle"), font=("Microsoft YaHei UI", 9), fg=self.colors["text_secondary"], bg=self.colors["card"])
        self.subtitle_label.pack(anchor="w", pady=(2, 0))
        self.scope_switch = tk.Frame(title_box, bg=self.colors["card"])
        self.scope_switch.pack(anchor="w", pady=(10, 0))
        self.personal_scope_btn = tk.Button(self.scope_switch, text=self.app.t("mode_personal"), command=lambda: self._switch_scope("personal"), relief=tk.FLAT, bd=0, font=("Microsoft YaHei UI", 9, "bold"), padx=12, pady=6, cursor="hand2")
        self.personal_scope_btn.pack(side=tk.LEFT, padx=(0, 8))
        self.enterprise_scope_btn = tk.Button(self.scope_switch, text=self.app.t("mode_enterprise"), command=lambda: self._switch_scope("enterprise"), relief=tk.FLAT, bd=0, font=("Microsoft YaHei UI", 9, "bold"), padx=12, pady=6, cursor="hand2")
        self.enterprise_scope_btn.pack(side=tk.LEFT)

        # Title/description are now shown in the global page header to avoid duplicate headings.
        try:
            icon.pack_forget()
            self.title_label.pack_forget()
            self.subtitle_label.pack_forget()
            title_box.pack_configure(padx=0)
            self.scope_switch.pack_configure(pady=(0, 0))
            bar.pack_configure(padx=18, pady=10)
        except Exception:
            pass

        self.open_folder_btn = create_button(bar, self.app.t("cloud_open_folder"), self.open_folder, self.colors)
        self.open_folder_btn.pack(side=tk.RIGHT)
        self.refresh_btn = create_button(bar, self.app.t("cloud_refresh"), self.refresh, self.colors)
        self.refresh_btn.pack(side=tk.RIGHT, padx=8)
        self.upload_btn = create_button(bar, self.app.t("cloud_upload"), self.upload_file, self.colors, filled=True)
        self.upload_btn.pack(side=tk.RIGHT)

        info_row = tk.Frame(self.frame, bg=self.colors["bg"])
        info_row.pack(fill=tk.X, pady=(0, 14))

        self.stat_files = self._stat_card(info_row, "cloud_total_files", "0")
        self.stat_size = self._stat_card(info_row, "cloud_total_size", "0 KB")
        self.info_card = create_card(info_row, self.colors)
        self.info_card.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(14, 0))
        self.local_label = tk.Label(self.info_card, text=self.app.t("cloud_local_only"), font=("Microsoft YaHei UI", 10, "bold"), fg=self.colors["text"], bg=self.colors["card"], wraplength=640, justify=tk.LEFT)
        self.local_label.pack(anchor="w", padx=16, pady=(14, 2))
        self.next_label = tk.Label(self.info_card, text=self.app.t("cloud_next_step"), font=("Microsoft YaHei UI", 9), fg=self.colors["text_secondary"], bg=self.colors["card"], wraplength=640, justify=tk.LEFT)
        self.next_label.pack(anchor="w", padx=16, pady=(2, 14))

        list_card = create_card(self.frame, self.colors, fill=tk.BOTH, expand=True)
        header = tk.Frame(list_card, bg=self.colors["card"])
        header.pack(fill=tk.X, padx=18, pady=(16, 10))
        self.files_title = tk.Label(header, text=f"{self.app.t('cloud_files')} · {self._scope_label()}", font=("Microsoft YaHei UI", 15, "bold"), fg=self.colors["text"], bg=self.colors["card"])
        self.files_title.pack(side=tk.LEFT)
        self.files_count = tk.Label(header, text="", font=("Microsoft YaHei UI", 9), fg=self.colors["text_secondary"], bg=self.colors["card"])
        self.files_count.pack(side=tk.RIGHT)

        self.list_frame = tk.Frame(list_card, bg=self.colors["card"])
        self.list_frame.pack(fill=tk.BOTH, expand=True, padx=14, pady=(0, 14))

    def _stat_card(self, parent, label_key, value):
        card = create_card(parent, self.colors)
        card.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 14))
        value_label = tk.Label(card, text=value, font=("Microsoft YaHei UI", 22, "bold"), fg=self.colors["primary"], bg=self.colors["card"])
        value_label.pack(anchor="w", padx=16, pady=(12, 0))
        label = tk.Label(card, text=self.app.t(label_key), font=("Microsoft YaHei UI", 9), fg=self.colors["text_secondary"], bg=self.colors["card"])
        label.pack(anchor="w", padx=16, pady=(0, 12))
        return {"card": card, "value": value_label, "label": label, "key": label_key}

    def refresh(self):
        self.upload_dir = self._current_upload_dir()
        self.upload_dir.mkdir(parents=True, exist_ok=True)
        self._update_scope_switch()
        for child in self.list_frame.winfo_children():
            child.destroy()

        files = self._scan_files()
        total_size = sum(item["size"] for item in files)
        self.stat_files["value"].config(text=str(len(files)))
        self.stat_files["label"].config(text=self.app.t("cloud_total_files"))
        self.stat_size["value"].config(text=self._format_size(total_size))
        self.stat_size["label"].config(text=self.app.t("cloud_total_size"))
        if hasattr(self, "files_count"):
            self.files_count.config(text=self.app.t("shared_items_count").format(count=len(files), scope=self._scope_label()))

        if not files:
            show_empty(self.list_frame, self.app.t("cloud_no_files"), self.colors)
            return

        for item in files:
            self._file_row(item)

    def update_language(self):
        self.title_label.config(text=self.app.t("cloud_title"))
        self.subtitle_label.config(text=self.app.t("cloud_subtitle"))
        if hasattr(self, "personal_scope_btn"):
            self.personal_scope_btn.config(text=self.app.t("mode_personal"))
        if hasattr(self, "enterprise_scope_btn"):
            self.enterprise_scope_btn.config(text=self.app.t("mode_enterprise"))
        self._update_scope_switch()
        self.open_folder_btn.config(text=self.app.t("cloud_open_folder"))
        self.refresh_btn.config(text=self.app.t("cloud_refresh"))
        self.upload_btn.config(text=self.app.t("cloud_upload"))
        self.local_label.config(text=self.app.t("cloud_local_only"))
        self.next_label.config(text=self.app.t("cloud_next_step"))
        self.files_title.config(text=f"{self.app.t('cloud_files')} · {self._scope_label()}")
        self.refresh()

    def _scan_files(self):
        result = []
        for path in sorted(self.upload_dir.rglob("*"), key=lambda p: p.stat().st_mtime if p.is_file() else 0, reverse=True):
            if not path.is_file():
                continue
            rel = path.relative_to(DATA_DIR).as_posix()
            doc_title = self._linked_doc_title(rel)
            try:
                stat = path.stat()
                result.append({
                    "path": path,
                    "rel": rel,
                    "name": path.name,
                    "size": stat.st_size,
                    "modified": datetime.fromtimestamp(stat.st_mtime).strftime("%Y-%m-%d %H:%M"),
                    "doc_title": doc_title,
                })
            except Exception:
                pass
        return result

    def _linked_doc_title(self, rel_path):
        docs = self.app.visible_documents() if hasattr(self.app, "visible_documents") else self.app.documents
        for doc in docs.values():
            attachment = doc.get("attachment") or {}
            if isinstance(attachment, dict):
                if attachment.get("path") == rel_path:
                    return self.app.display_doc_title(doc.get("title", ""))
            elif isinstance(attachment, str) and attachment.replace("\\", "/").endswith(rel_path):
                return self.app.display_doc_title(doc.get("title", ""))
        return ""

    def _file_row(self, item):
        row = tk.Frame(self.list_frame, bg=self.colors["card_soft"], highlightthickness=1, highlightbackground=self.colors["border"])
        row.pack(fill=tk.X, pady=5)

        left = tk.Frame(row, bg=self.colors["card_soft"], cursor="hand2")
        left.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=14, pady=10)

        name = tk.Label(left, text=item["name"], font=("Microsoft YaHei UI", 10, "bold"), fg=self.colors["text"], bg=self.colors["card_soft"], anchor="w")
        name.pack(anchor="w")
        meta = f"{self.app.t('cloud_size')}: {self._format_size(item['size'])}   ·   {self.app.t('cloud_modified')}: {item['modified']}"
        if item["doc_title"]:
            meta += f"   ·   {self.app.t('cloud_linked_doc')}: {item['doc_title']}"
        tk.Label(left, text=meta, font=("Microsoft YaHei UI", 8), fg=self.colors["text_secondary"], bg=self.colors["card_soft"], anchor="w").pack(anchor="w", pady=(4, 0))

        open_btn = tk.Button(row, text="↗", command=lambda p=item["path"]: self.open_file(p), relief=tk.FLAT, bd=0, bg=self.colors["card_soft"], fg=self.colors["primary"], activebackground=self.colors["primary_light"], activeforeground=self.colors["primary"], cursor="hand2", font=("Microsoft YaHei UI", 11, "bold"))
        open_btn.pack(side=tk.RIGHT, padx=(0, 6))
        ToolTip(open_btn, lambda: self.app.t("tooltip_open_file"))

        del_btn = tk.Button(row, text="×", command=lambda p=item["path"]: self.delete_file(p), relief=tk.FLAT, bd=0, bg=self.colors["card_soft"], fg=self.colors["danger"], activebackground=self.colors["danger_light"], activeforeground=self.colors["danger"], cursor="hand2", font=("Microsoft YaHei UI", 12, "bold"))
        del_btn.pack(side=tk.RIGHT, padx=10)
        ToolTip(del_btn, lambda: self.app.t("tooltip_delete_file"))

        left.bind("<Double-Button-1>", lambda e, p=item["path"]: self.open_file(p))
        name.bind("<Double-Button-1>", lambda e, p=item["path"]: self.open_file(p))

    def upload_file(self):
        path = filedialog.askopenfilename(filetypes=[("All files", "*.*")])
        if not path:
            return
        src = Path(path)
        self.upload_dir.mkdir(parents=True, exist_ok=True)
        safe_name = src.name.replace("/", "_").replace("\\", "_")
        target = self.upload_dir / f"{int(time.time() * 1000)}_{safe_name}"
        shutil.copy2(src, target)
        self.app.set_status("status_saved")
        self.refresh()

    def open_folder(self):
        self.upload_dir = self._current_upload_dir()
        self.upload_dir.mkdir(parents=True, exist_ok=True)
        self.open_file(self.upload_dir)

    def open_file(self, path):
        path = Path(path)
        if not path.exists():
            messagebox.showwarning(self.app.t("warning_title") if "warning_title" in self.app.lang else self.app.t("confirm_title"), self.app.t("cloud_file_open_failed"))
            return
        try:
            if sys.platform.startswith("win"):
                os.startfile(str(path))
            elif sys.platform == "darwin":
                subprocess.Popen(["open", str(path)])
            else:
                subprocess.Popen(["xdg-open", str(path)])
        except Exception:
            messagebox.showwarning(self.app.t("confirm_title"), self.app.t("cloud_file_open_failed"))

    def delete_file(self, path):
        path = Path(path)
        if not path.exists():
            self.refresh()
            return
        if not messagebox.askyesno(self.app.t("confirm_title"), self.app.t("cloud_confirm_delete")):
            return
        try:
            path.unlink()
            self.app.set_status("status_saved")
        except Exception:
            messagebox.showwarning(self.app.t("confirm_title"), self.app.t("cloud_file_open_failed"))
        self.refresh()

    def _format_size(self, size):
        size = float(size)
        units = ["B", "KB", "MB", "GB"]
        idx = 0
        while size >= 1024 and idx < len(units) - 1:
            size /= 1024
            idx += 1
        if idx == 0:
            return f"{int(size)} {units[idx]}"
        return f"{size:.1f} {units[idx]}"
