#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
枪械计算器 - 图形界面版
使用 tkinter 实现，提供便捷的枪械参数输入和实时计算。
"""

import math
import tkinter as tk
from tkinter import ttk, messagebox

# ---------- 核心计算类 ----------


class GunCalculator:
    """枪械计算器核心类"""
    # 常见枪械数据：名称, 弹头质量(g), 初速(m/s), 弹道系数(粗略)
    COMMON_GUNS = {
        "9mm手枪": (8.0, 360, 0.15),
        ".45 ACP": (15.0, 255, 0.20),
        "5.56mm步枪": (4.0, 940, 0.30),
        "7.62mm步枪": (8.0, 830, 0.35),
        ".308 Win": (11.0, 820, 0.40),
        ".338 Lapua": (16.2, 890, 0.55),
        "12号霰弹": (28.0, 400, 0.10),
    }

    def __init__(self):
        self.bullet_mass_kg = 0.0
        self.muzzle_velocity = 0.0
        self.drag_coefficient = 0.2

    def set_params(self, mass_g, velocity_ms, bc=0.2):
        self.bullet_mass_kg = mass_g / 1000.0
        self.muzzle_velocity = velocity_ms
        self.drag_coefficient = bc

    def kinetic_energy(self):
        if self.bullet_mass_kg <= 0 or self.muzzle_velocity <= 0:
            return 0.0
        return 0.5 * self.bullet_mass_kg * self.muzzle_velocity ** 2

    def momentum(self):
        if self.bullet_mass_kg <= 0 or self.muzzle_velocity <= 0:
            return 0.0
        return self.bullet_mass_kg * self.muzzle_velocity

    def bullet_drop(self, distance_m, g=9.81):
        if self.muzzle_velocity <= 0 or distance_m <= 0:
            return 0.0
        t = distance_m / self.muzzle_velocity
        drop = 0.5 * g * t ** 2
        return drop, t

    def effective_range_est(self, min_energy_j=100):
        e0 = self.kinetic_energy()
        if e0 <= min_energy_j:
            return 0.0
        # 衰减系数简化模型
        k = 0.01 / (self.drag_coefficient if self.drag_coefficient > 0 else 0.1)
        d = math.log(e0 / min_energy_j) / k
        return max(0, d)


# ---------- GUI 应用 ----------
class GunCalculatorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("枪械计算器")
        self.root.geometry("500x650")
        self.root.resizable(False, False)

        # 初始化计算器实例
        self.calc = GunCalculator()

        # 创建界面组件
        self.create_widgets()

        # 默认填入一组数据（可选）
        self.calc.set_params(8.0, 360, 0.15)
        self.update_current_info()

    def create_widgets(self):
        """创建所有界面元素"""
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)

        # ----- 参数输入区域 -----
        param_frame = ttk.LabelFrame(main_frame, text="枪械参数", padding="5")
        param_frame.pack(fill=tk.X, pady=5)

        # 质量
        ttk.Label(param_frame, text="弹头质量 (克):").grid(
            row=0, column=0, sticky=tk.W, padx=5, pady=2)
        self.mass_entry = ttk.Entry(param_frame, width=15)
        self.mass_entry.grid(row=0, column=1, padx=5, pady=2)

        # 初速
        ttk.Label(param_frame, text="初速 (米/秒):").grid(row=1,
                                                      column=0, sticky=tk.W, padx=5, pady=2)
        self.vel_entry = ttk.Entry(param_frame, width=15)
        self.vel_entry.grid(row=1, column=1, padx=5, pady=2)

        # 弹道系数
        ttk.Label(param_frame, text="弹道系数 (0.1~0.6):").grid(
            row=2, column=0, sticky=tk.W, padx=5, pady=2)
        self.bc_entry = ttk.Entry(param_frame, width=15)
        self.bc_entry.grid(row=2, column=1, padx=5, pady=2)

        # 按钮：应用参数
        self.apply_btn = ttk.Button(
            param_frame, text="应用参数", command=self.apply_params)
        self.apply_btn.grid(row=3, column=0, columnspan=2, pady=5)

        # ----- 常见枪械下拉框 -----
        gun_frame = ttk.LabelFrame(main_frame, text="常见枪械", padding="5")
        gun_frame.pack(fill=tk.X, pady=5)

        self.gun_combo = ttk.Combobox(gun_frame, values=list(
            GunCalculator.COMMON_GUNS.keys()), state="readonly")
        self.gun_combo.pack(fill=tk.X, padx=5, pady=2)
        self.gun_combo.bind("<<ComboboxSelected>>", self.on_gun_selected)

        # ----- 显示当前参数和主要指标 -----
        info_frame = ttk.LabelFrame(main_frame, text="当前枪械信息", padding="5")
        info_frame.pack(fill=tk.X, pady=5)

        self.info_text = tk.Text(info_frame, height=6,
                                 width=50, state=tk.DISABLED)
        self.info_text.pack(fill=tk.X, padx=5, pady=2)

        # ----- 弹道下坠计算 -----
        drop_frame = ttk.LabelFrame(main_frame, text="弹道下坠", padding="5")
        drop_frame.pack(fill=tk.X, pady=5)

        ttk.Label(drop_frame, text="目标距离 (米):").grid(
            row=0, column=0, sticky=tk.W, padx=5, pady=2)
        self.distance_entry = ttk.Entry(drop_frame, width=15)
        self.distance_entry.grid(row=0, column=1, padx=5, pady=2)
        self.calc_drop_btn = ttk.Button(
            drop_frame, text="计算下坠", command=self.calc_drop)
        self.calc_drop_btn.grid(row=0, column=2, padx=5, pady=2)

        self.drop_result = ttk.Label(drop_frame, text="下坠: --  飞行时间: --")
        self.drop_result.grid(row=1, column=0, columnspan=3, pady=5)

        # ----- 有效射程估算 -----
        range_frame = ttk.LabelFrame(main_frame, text="有效射程估算", padding="5")
        range_frame.pack(fill=tk.X, pady=5)

        ttk.Label(range_frame, text="最小动能 (焦耳):").grid(
            row=0, column=0, sticky=tk.W, padx=5, pady=2)
        self.min_energy_entry = ttk.Entry(range_frame, width=10)
        self.min_energy_entry.insert(0, "100")  # 默认100J
        self.min_energy_entry.grid(row=0, column=1, padx=5, pady=2)
        self.calc_range_btn = ttk.Button(
            range_frame, text="估算射程", command=self.calc_range)
        self.calc_range_btn.grid(row=0, column=2, padx=5, pady=2)

        self.range_result = ttk.Label(range_frame, text="有效射程: -- 米")
        self.range_result.grid(row=1, column=0, columnspan=3, pady=5)

        # 提示标签
        note = ttk.Label(main_frame, text="注：弹道下坠为真空近似，有效射程基于简化动能衰减模型，仅供参考。",
                         foreground="gray", wraplength=460)
        note.pack(pady=5)

    def apply_params(self):
        """从输入框读取参数并应用到计算器"""
        try:
            mass = float(self.mass_entry.get())
            vel = float(self.vel_entry.get())
            bc_str = self.bc_entry.get().strip()
            bc = float(bc_str) if bc_str else 0.2
            if mass <= 0 or vel <= 0:
                raise ValueError("质量和速度必须为正数")
            self.calc.set_params(mass, vel, bc)
            self.update_current_info()
        except ValueError as e:
            messagebox.showerror("输入错误", f"请输入有效的数字\n{str(e)}")

    def on_gun_selected(self, event):
        """当选择常见枪械时自动填充参数"""
        name = self.gun_combo.get()
        if name in GunCalculator.COMMON_GUNS:
            mass, vel, bc = GunCalculator.COMMON_GUNS[name]
            self.mass_entry.delete(0, tk.END)
            self.mass_entry.insert(0, str(mass))
            self.vel_entry.delete(0, tk.END)
            self.vel_entry.insert(0, str(vel))
            self.bc_entry.delete(0, tk.END)
            self.bc_entry.insert(0, str(bc))
            # 自动应用参数
            self.calc.set_params(mass, vel, bc)
            self.update_current_info()

    def update_current_info(self):
        """更新信息显示区域"""
        mass_g = self.calc.bullet_mass_kg * 1000
        vel = self.calc.muzzle_velocity
        bc = self.calc.drag_coefficient
        ke = self.calc.kinetic_energy()
        mom = self.calc.momentum()

        self.info_text.config(state=tk.NORMAL)
        self.info_text.delete(1.0, tk.END)
        info = (f"弹头质量: {mass_g:.1f} g\n"
                f"初速: {vel:.1f} m/s\n"
                f"弹道系数: {bc:.2f}\n"
                f"枪口动能: {ke:.1f} J\n"
                f"动量: {mom:.3f} kg·m/s")
        self.info_text.insert(tk.END, info)
        self.info_text.config(state=tk.DISABLED)

    def calc_drop(self):
        """计算弹道下坠"""
        if self.calc.muzzle_velocity <= 0:
            messagebox.showwarning("未设置参数", "请先设置枪械参数")
            return
        try:
            dist = float(self.distance_entry.get())
            if dist <= 0:
                raise ValueError
            drop, t = self.calc.bullet_drop(dist)
            self.drop_result.config(
                text=f"下坠: {drop*1000:.1f} mm ({drop:.3f} m)  飞行时间: {t*1000:.1f} ms")
        except ValueError:
            messagebox.showerror("输入错误", "请输入有效的正数距离")

    def calc_range(self):
        """估算有效射程"""
        if self.calc.muzzle_velocity <= 0:
            messagebox.showwarning("未设置参数", "请先设置枪械参数")
            return
        try:
            min_energy = float(self.min_energy_entry.get())
            if min_energy <= 0:
                raise ValueError
            eff_range = self.calc.effective_range_est(min_energy)
            self.range_result.config(
                text=f"有效射程: {eff_range:.0f} 米 (基于动能不低于 {min_energy:.0f} J)")
        except ValueError:
            messagebox.showerror("输入错误", "请输入有效的正数动能")


if __name__ == "__main__":
    root = tk.Tk()
    app = GunCalculatorApp(root)
    root.mainloop()
