import tkinter as tk
from tkinter import ttk, messagebox
import sqlite3

class CustomerDB:
    """データベース操作を管理するクラス"""
    def __init__(self, db_name="customer_management.db"):
        self.conn = sqlite3.connect(db_name)
        self.cursor = self.conn.cursor()
        self.create_table()

    def create_table(self):
        """顧客テーブルが存在しない場合に作成する"""
        self.cursor.execute("""
            CREATE TABLE IF NOT EXISTS customers (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT NOT NULL,
                kana TEXT,
                address TEXT,
                phone TEXT,
                email TEXT
            )
        """)
        self.conn.commit()

    def fetch_all(self):
        """全ての顧客情報を取得する (顧客ID順)"""
        self.cursor.execute("SELECT * FROM customers ORDER BY id")
        return self.cursor.fetchall()

    def search(self, keyword):
        """指定されたキーワードで全項目を検索する"""
        query = """
            SELECT * FROM customers WHERE
            name LIKE ? OR
            kana LIKE ? OR
            address LIKE ? OR
            phone LIKE ? OR
            email LIKE ?
            ORDER BY id
        """
        like_keyword = f"%{keyword}%"
        self.cursor.execute(query, (like_keyword, like_keyword, like_keyword, like_keyword, like_keyword))
        return self.cursor.fetchall()

    def add(self, customer_data):
        """新しい顧客情報を追加する"""
        query = "INSERT INTO customers (name, kana, address, phone, email) VALUES (?, ?, ?, ?, ?)"
        self.cursor.execute(query, (
            customer_data['name'],
            customer_data['kana'],
            customer_data['address'],
            customer_data['phone'],
            customer_data['email']
        ))
        self.conn.commit()

    def update(self, customer_id, customer_data):
        """顧客情報を更新する"""
        query = """
            UPDATE customers SET
            name = ?, kana = ?, address = ?, phone = ?, email = ?
            WHERE id = ?
        """
        self.cursor.execute(query, (
            customer_data['name'],
            customer_data['kana'],
            customer_data['address'],
            customer_data['phone'],
            customer_data['email'],
            customer_id
        ))
        self.conn.commit()

    def delete(self, customer_id):
        """顧客情報を削除する"""
        self.cursor.execute("DELETE FROM customers WHERE id = ?", (customer_id,))
        self.conn.commit()

    def __del__(self):
        """インスタンス破棄時にデータベース接続を閉じる"""
        self.conn.close()

class BaseWindow:
    """ウィンドウの基本設定（中央表示など）を行うクラス"""
    def center_window(self, window, width, height):
        """ウィンドウを画面中央に配置する"""
        screen_width = window.winfo_screenwidth()
        screen_height = window.winfo_screenheight()
        x = (screen_width // 2) - (width // 2)
        y = (screen_height // 2) - (height // 2)
        window.geometry(f'{width}x{height}+{x}+{y}')
        window.update_idletasks() # ウィンドウサイズが確定するのを待つ

class CustomerInfoWindow(BaseWindow):
    """顧客情報の登録・更新・削除画面の基底クラス"""
    def __init__(self, parent, title):
        self.top = tk.Toplevel(parent)
        self.top.title(title)
        self.top.grab_set() # モーダルウィンドウにする
        self.top.focus_set()

        # ウィジェットの作成
        self.create_widgets()
        
        # ウィンドウサイズをウィジェットに合わせて調整し、中央に表示
        self.top.update_idletasks()
        width = self.top.winfo_reqwidth()
        height = self.top.winfo_reqheight()
        self.center_window(self.top, width, height)


    def create_widgets(self):
        """入力フォームとボタンを配置する"""
        main_frame = ttk.Frame(self.top, padding=10)
        main_frame.pack(fill=tk.BOTH, expand=True)

        # --- 入力フィールド ---
        form_frame = ttk.Frame(main_frame)
        form_frame.pack(fill=tk.X, expand=True)

        ttk.Label(form_frame, text="顧客名 (必須):").grid(row=0, column=0, sticky=tk.W, padx=5, pady=5)
        self.name_entry = ttk.Entry(form_frame, width=40)
        self.name_entry.grid(row=0, column=1, sticky=tk.EW, padx=5, pady=5)

        ttk.Label(form_frame, text="フリガナ:").grid(row=1, column=0, sticky=tk.W, padx=5, pady=5)
        self.kana_entry = ttk.Entry(form_frame, width=40)
        self.kana_entry.grid(row=1, column=1, sticky=tk.EW, padx=5, pady=5)

        ttk.Label(form_frame, text="住所:").grid(row=2, column=0, sticky=tk.NW, padx=5, pady=5)
        self.address_text = tk.Text(form_frame, width=40, height=5)
        self.address_text.grid(row=2, column=1, sticky=tk.EW, padx=5, pady=5)
        # スクロールバーを追加
        address_scrollbar = ttk.Scrollbar(form_frame, orient=tk.VERTICAL, command=self.address_text.yview)
        address_scrollbar.grid(row=2, column=2, sticky=tk.NS)
        self.address_text['yscrollcommand'] = address_scrollbar.set

        ttk.Label(form_frame, text="電話番号:").grid(row=3, column=0, sticky=tk.W, padx=5, pady=5)
        self.phone_entry = ttk.Entry(form_frame, width=40)
        self.phone_entry.grid(row=3, column=1, sticky=tk.EW, padx=5, pady=5)

        ttk.Label(form_frame, text="メールアドレス:").grid(row=4, column=0, sticky=tk.W, padx=5, pady=5)
        self.email_entry = ttk.Entry(form_frame, width=40)
        self.email_entry.grid(row=4, column=1, sticky=tk.EW, padx=5, pady=5)
        
        form_frame.grid_columnconfigure(1, weight=1)

        # --- ボタン ---
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill=tk.X, pady=10)
        button_frame.grid_columnconfigure(0, weight=1)
        button_frame.grid_columnconfigure(1, weight=1)
        button_frame.grid_columnconfigure(2, weight=1)

        self.setup_buttons(button_frame)
    
    def setup_buttons(self, frame):
        """各画面固有のボタンを配置する（サブクラスでオーバーライド）"""
        pass

    def get_form_data(self):
        """フォームから入力データを取得する"""
        return {
            'name': self.name_entry.get(),
            'kana': self.kana_entry.get(),
            'address': self.address_text.get("1.0", tk.END).strip(),
            'phone': self.phone_entry.get(),
            'email': self.email_entry.get()
        }

class RegisterWindow(CustomerInfoWindow):
    """顧客登録画面"""
    def __init__(self, parent, db, on_close_callback):
        self.db = db
        self.on_close_callback = on_close_callback
        super().__init__(parent, "顧客新規登録")

    def setup_buttons(self, frame):
        ttk.Button(frame, text="登録", command=self.register_customer).grid(row=0, column=0, padx=5, sticky=tk.E)
        ttk.Button(frame, text="キャンセル", command=self.top.destroy).grid(row=0, column=1, padx=5, sticky=tk.W)

    def register_customer(self):
        data = self.get_form_data()
        if not data['name']:
            messagebox.showerror("入力エラー", "顧客名は必須項目です。", parent=self.top)
            return
        
        try:
            self.db.add(data)
            messagebox.showinfo("成功", "顧客情報を登録しました。", parent=self.top)
            self.on_close_callback()
            self.top.destroy()
        except Exception as e:
            messagebox.showerror("エラー", f"登録中にエラーが発生しました: {e}", parent=self.top)


class UpdateDeleteWindow(CustomerInfoWindow):
    """顧客情報更新・削除画面"""
    def __init__(self, parent, db, customer_info, on_close_callback):
        self.db = db
        self.customer_info = customer_info
        self.customer_id = customer_info[0]
        self.on_close_callback = on_close_callback
        super().__init__(parent, "顧客情報更新・削除")
        self.populate_form()

    def setup_buttons(self, frame):
        ttk.Button(frame, text="更新", command=self.update_customer).grid(row=0, column=0, padx=5, sticky=tk.E)
        ttk.Button(frame, text="削除", command=self.delete_customer).grid(row=0, column=1, padx=5)
        ttk.Button(frame, text="キャンセル", command=self.top.destroy).grid(row=0, column=2, padx=5, sticky=tk.W)

    def populate_form(self):
        """フォームに既存の顧客情報を表示する"""
        self.name_entry.insert(0, self.customer_info[1])
        self.kana_entry.insert(0, self.customer_info[2])
        self.address_text.insert("1.0", self.customer_info[3])
        self.phone_entry.insert(0, self.customer_info[4])
        self.email_entry.insert(0, self.customer_info[5])

    def update_customer(self):
        data = self.get_form_data()
        if not data['name']:
            messagebox.showerror("入力エラー", "顧客名は必須項目です。", parent=self.top)
            return
        
        try:
            self.db.update(self.customer_id, data)
            messagebox.showinfo("成功", "顧客情報を更新しました。", parent=self.top)
            self.on_close_callback()
            self.top.destroy()
        except Exception as e:
            messagebox.showerror("エラー", f"更新中にエラーが発生しました: {e}", parent=self.top)
    
    def delete_customer(self):
        if messagebox.askyesno("削除確認", "本当にこの顧客情報を削除しますか？", parent=self.top):
            try:
                self.db.delete(self.customer_id)
                messagebox.showinfo("成功", "顧客情報を削除しました。", parent=self.top)
                self.on_close_callback()
                self.top.destroy()
            except Exception as e:
                messagebox.showerror("エラー", f"削除中にエラーが発生しました: {e}", parent=self.top)


class Application(tk.Frame, BaseWindow):
    """メインアプリケーションウィンドウ（顧客一覧画面）"""
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.master.title("顧客管理システム")
        
        # データベースインスタンス
        self.db = CustomerDB()
        
        # ウィジェットの作成と配置
        self.create_widgets()
        
        # 顧客リストの初期表示
        self.populate_customer_list()

        # ウィンドウサイズを調整して中央に表示
        self.master.update_idletasks()
        width = self.master.winfo_reqwidth()
        height = self.master.winfo_reqheight()
        self.center_window(self.master, width, height)


    def create_widgets(self):
        """ウィジェットを作成・配置する"""
        main_frame = ttk.Frame(self.master, padding=10)
        main_frame.pack(fill=tk.BOTH, expand=True)

        # --- 検索フレーム ---
        search_frame = ttk.Frame(main_frame)
        search_frame.pack(fill=tk.X, pady=(0, 10))
        
        ttk.Label(search_frame, text="検索:").pack(side=tk.LEFT, padx=(0, 5))
        self.search_entry = ttk.Entry(search_frame)
        self.search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)
        self.search_entry.bind('<Return>', self.search_customers) # Enterキーでも検索
        ttk.Button(search_frame, text="検索", command=self.search_customers).pack(side=tk.LEFT, padx=(5, 0))
        ttk.Button(search_frame, text="クリア", command=self.clear_search).pack(side=tk.LEFT, padx=(5, 0))

        # --- 顧客一覧 (Treeview) ---
        tree_frame = ttk.Frame(main_frame)
        tree_frame.pack(fill=tk.BOTH, expand=True)
        
        columns = ("id", "name", "kana", "phone", "email")
        self.tree = ttk.Treeview(tree_frame, columns=columns, show="headings")
        
        self.tree.heading("id", text="顧客ID")
        self.tree.heading("name", text="顧客名")
        self.tree.heading("kana", text="フリガナ")
        self.tree.heading("phone", text="電話番号")
        self.tree.heading("email", text="メールアドレス")
        
        self.tree.column("id", width=60, anchor=tk.CENTER)
        self.tree.column("name", width=150)
        self.tree.column("kana", width=150)
        self.tree.column("phone", width=120)
        self.tree.column("email", width=200)

        # スクロールバー
        vsb = ttk.Scrollbar(tree_frame, orient="vertical", command=self.tree.yview)
        hsb = ttk.Scrollbar(tree_frame, orient="horizontal", command=self.tree.xview)
        self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set)

        self.tree.grid(row=0, column=0, sticky="nsew")
        vsb.grid(row=0, column=1, sticky="ns")
        hsb.grid(row=1, column=0, sticky="ew")

        tree_frame.grid_rowconfigure(0, weight=1)
        tree_frame.grid_columnconfigure(0, weight=1)

        # --- ボタンフレーム ---
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill=tk.X, pady=(10, 0))
        
        ttk.Button(button_frame, text="新規登録", command=self.open_register_window).pack(side=tk.LEFT)
        ttk.Button(button_frame, text="更新・削除", command=self.open_update_delete_window).pack(side=tk.LEFT, padx=5)

    def populate_customer_list(self, customers=None):
        """Treeviewに顧客データを表示する"""
        for i in self.tree.get_children():
            self.tree.delete(i)
        
        if customers is None:
            customers = self.db.fetch_all()
            
        for customer in customers:
            # 住所は一覧に表示しない
            self.tree.insert("", "end", values=(customer[0], customer[1], customer[2], customer[4], customer[5]))

    def search_customers(self, event=None):
        """検索を実行して結果を表示する"""
        keyword = self.search_entry.get()
        if keyword:
            customers = self.db.search(keyword)
            self.populate_customer_list(customers)
        else:
            self.populate_customer_list()
    
    def clear_search(self):
        """検索をクリアして全件表示に戻す"""
        self.search_entry.delete(0, tk.END)
        self.populate_customer_list()

    def open_register_window(self):
        """新規登録ウィンドウを開く"""
        RegisterWindow(self.master, self.db, self.populate_customer_list)
        
    def open_update_delete_window(self):
        """更新・削除ウィンドウを開く"""
        selected_item = self.tree.focus()
        if not selected_item:
            messagebox.showwarning("選択エラー", "一覧から顧客を選択してください。")
            return
        
        item_values = self.tree.item(selected_item)['values']
        customer_id = item_values[0]
        
        # 全ての情報を取得するために再度DBから検索
        # (一覧表示には住所などが含まれていないため)
        full_info = self.db.search(f"id = {customer_id}")
        if not full_info:
            # 検索で見つからない場合は、IDで直接検索を試みる
            self.db.cursor.execute("SELECT * FROM customers WHERE id = ?", (customer_id,))
            full_info = self.db.cursor.fetchall()

        if full_info:
             UpdateDeleteWindow(self.master, self.db, full_info[0], self.populate_customer_list)
        else:
            messagebox.showerror("エラー", "選択された顧客情報の取得に失敗しました。")
            self.populate_customer_list() # リストをリフレッシュ

if __name__ == "__main__":
    root = tk.Tk()
    app = Application(master=root)
    root.mainloop()