"""AppUserModelID + ярлык в меню «Пуск» — без этого Windows-toast не показываются."""

from __future__ import annotations

import logging
import os
import subprocess
import sys
from pathlib import Path

from paths import get_icon_ico_path

logger = logging.getLogger(__name__)

APP_ID = "AXON.DumpRadar"


def _exe_path() -> Path:
    if getattr(sys, "frozen", False):
        return Path(sys.executable).resolve()
    return (Path(__file__).resolve().parent / "entry.py").resolve()


def _marker_path() -> Path:
    return Path(os.environ.get("APPDATA", str(Path.home()))) / "AXON-Dump-Radar" / "aumid.txt"


def _shortcut_path() -> Path:
    return (
        Path(os.environ.get("APPDATA", str(Path.home())))
        / "Microsoft"
        / "Windows"
        / "Start Menu"
        / "Programs"
        / "AXON Dump Radar.lnk"
    )


def _create_shortcut_ps(exe: Path, shortcut: Path, app_id: str, icon: Path | None = None) -> bool:
    shortcut.parent.mkdir(parents=True, exist_ok=True)
    exe_s = str(exe).replace("'", "''")
    sc_s = str(shortcut).replace("'", "''")
    icon_s = str(icon).replace("'", "''") if icon and icon.exists() else ""
    ps = f"""
$ErrorActionPreference = 'Stop'
Add-Type @"
using System;
using System.Runtime.InteropServices;
using System.Text;

public class AxonShellLink {{
    [ComImport, Guid("000214F9-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    interface IShellLinkW {{
        void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, IntPtr pfd, int fFlags);
        void GetIDList(out IntPtr ppidl);
        void SetIDList(IntPtr pidl);
        void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
        void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
        void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
        void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
        void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
        void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
        void GetHotkey(out short pwHotkey);
        void SetHotkey(short wHotkey);
        void GetShowCmd(out int piShowCmd);
        void SetShowCmd(int iShowCmd);
        void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon);
        void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
        void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPath, int dwReserved);
        void Resolve(IntPtr hwnd, int fFlags);
        void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
    }}

    [ComImport, Guid("0000010c-0000-0000-c000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    interface IPropertyStore {{
        void GetCount(out uint cProps);
        void GetAt(uint iProp, out PROPERTYKEY pkey);
        void GetValue(ref PROPERTYKEY key, out PROPVARIANT pv);
        void SetValue(ref PROPERTYKEY key, ref PROPVARIANT pv);
        void Commit();
    }}

    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public struct PROPERTYKEY {{
        public Guid fmtid;
        public uint pid;
    }}

    [StructLayout(LayoutKind.Explicit, Pack = 4)]
    public struct PROPVARIANT {{
        [FieldOffset(0)] public ushort vt;
        [FieldOffset(8)] public IntPtr pwszVal;
    }}

    [ComImport, Guid("00021401-0000-0000-C000-000000000046")]
    class ShellLink {{ }}

    [ComImport, Guid("00000109-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    interface IPersistFile {{
        void GetClassID(out Guid pClassID);
        [PreserveSig] int IsDirty();
        void Load([MarshalAs(UnmanagedType.LPWStr)] string pszFileName, uint dwMode);
        void Save([MarshalAs(UnmanagedType.LPWStr)] string pszFileName, bool fRemember);
        void SaveCompleted([MarshalAs(UnmanagedType.LPWStr)] string pszFileName);
        void GetCurFile([MarshalAs(UnmanagedType.LPWStr)] out string ppszFileName);
    }}

    public static void Create(string shortcutPath, string targetPath, string appId, string iconPath) {{
        var link = (IShellLinkW)new ShellLink();
        link.SetPath(targetPath);
        link.SetWorkingDirectory(System.IO.Path.GetDirectoryName(targetPath));
        if (!string.IsNullOrWhiteSpace(iconPath) && System.IO.File.Exists(iconPath)) {{
            link.SetIconLocation(iconPath, 0);
        }}

        var store = (IPropertyStore)link;
        var key = new PROPERTYKEY {{ fmtid = new Guid("9F4C2855-9F79-4F39-A8D0-E1D42D1E4353"), pid = 5 }};
        var pv = new PROPVARIANT {{ vt = 31, pwszVal = Marshal.StringToCoTaskMemUni(appId) }};
        store.SetValue(ref key, ref pv);
        store.Commit();

        var file = (IPersistFile)link;
        file.Save(shortcutPath, true);
    }}
}}
"@

[AxonShellLink]::Create('{sc_s}', '{exe_s}', '{app_id}', '{icon_s}')
"""
    try:
        subprocess.run(
            ["powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", ps],
            check=True,
            capture_output=True,
            text=True,
            timeout=30,
            creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0),
        )
        return shortcut.exists()
    except Exception as e:
        logger.warning("shortcut create failed: %s", e)
        return False


def setup_app_notifications() -> None:
    if sys.platform != "win32":
        return

    import ctypes

    ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(APP_ID)

    exe = _exe_path()
    marker = _marker_path()
    shortcut = _shortcut_path()
    marker.parent.mkdir(parents=True, exist_ok=True)

    from panel_defaults import PANEL_APP_VERSION

    icon = get_icon_ico_path() if getattr(sys, "frozen", False) else None
    exe_key = f"{PANEL_APP_VERSION}|{exe}|{icon}" if icon and icon.exists() else f"{PANEL_APP_VERSION}|{exe}"
    if marker.exists() and marker.read_text(encoding="utf-8").strip() == exe_key and shortcut.exists():
        return

    if getattr(sys, "frozen", False):
        ok = _create_shortcut_ps(exe, shortcut, APP_ID, icon)
        if ok:
            marker.write_text(exe_key, encoding="utf-8")
    else:
        marker.write_text(exe_key, encoding="utf-8")
