improve upgrade and revise: import sys
import json
import os
from datetime import datetime
import smtplib
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
import pandas as pd
from PyQt6 import QtWidgets, QtGui, QtCore
from PyQt6.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QTabWidget, QHBoxLayout,
    QLabel, QLineEdit, QPushButton, QMessageBox, QComboBox,
    QTextEdit, QListWidget, QListWidgetItem, QFileDialog, QSpinBox, QDialog, QTableWidget, QAbstractItemView
)
from PyQt6.QtCore import Qt
from openpyxl.utils.dataframe import dataframe_to_rows

# Define file paths
CLIENTS_FILE = 'clients.json'
LINE_ITEMS_FILE = 'line_items.json'
INVOICES_DIR = 'invoices'
COMPANY_DETAILS_FILE = 'company_details.json'
INVOICES_METADATA_FILE = 'invoices.json'

# Ensure necessary directories exist
os.makedirs(INVOICES_DIR, exist_ok=True)

# Function to load data from JSON
def load_json(file_path):
    if os.path.exists(file_path):
        try:
            with open(file_path, 'r') as f:
                return json.load(f)
        except json.JSONDecodeError:
            return {}
    return {}

# Function to save data to JSON
def save_json(data, file_path):
    with open(file_path, 'w') as f:
        json.dump(data, f, indent=4)

# Main Application Class
class InvoiceApp(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.clients = load_json(CLIENTS_FILE)
        self.line_items_data = load_json(LINE_ITEMS_FILE)
        self.company_details = load_json(COMPANY_DETAILS_FILE)
        self.invoices_metadata = load_json(INVOICES_METADATA_FILE)
        self.invoice_counter = self.get_next_invoice_number()
        self.init_ui()

    def get_next_invoice_number(self):
        """Gets the next available invoice number."""
        if os.path.exists("invoice_counter.txt"):
            with open("invoice_counter.txt", "r") as f:
                try:
                    counter = int(f.read())
                    return counter + 1
                except ValueError:
                    return 1
        else:
            return 1

    def update_invoice_counter(self):
        """Updates the invoice counter file."""
        with open("invoice_counter.txt", "w") as f:
            f.write(str(self.invoice_counter))

    def init_ui(self):
        self.setWindowTitle("Invoice Management Tool")
        self.setGeometry(100, 100, 1400, 900)
        layout = QVBoxLayout()

        # Apply Dark Theme
        self.apply_dark_theme()

        # Tab Widget
        self.tabs = QTabWidget()
        layout.addWidget(self.tabs)

        # Tabs
        self.client_tab = ClientManagementTab(self)
        self.line_item_tab = LineItemManagementTab(self)
        self.invoice_tab = InvoiceCreationTab(self)
        self.manage_invoices_tab = ManageInvoicesTab(self)
        self.financial_statements_tab = FinancialStatementsTab(self)
        self.company_details_tab = CompanyDetailsTab(self)

        self.tabs.addTab(self.client_tab, "Clients")
        self.tabs.addTab(self.line_item_tab, "Line Items")
        self.tabs.addTab(self.invoice_tab, "Create Invoice")
        self.tabs.addTab(self.manage_invoices_tab, "Manage Invoices")
        self.tabs.addTab(self.financial_statements_tab, "Financial Statements")
        self.tabs.addTab(self.company_details_tab, "Company Details")

        # Log Message Area
        self.log_area = QTextEdit(self)
        self.log_area.setReadOnly(True)
        self.log_area.setStyleSheet("""
            background-color: #1E1E1E;
            color: #ffffff;
            font-family: Consolas;
            font-size: 12px;
            border: 1px solid #555555;
        """)
        log_layout = QVBoxLayout()
        log_layout.addWidget(QLabel("Log:"))
        log_layout.addWidget(self.log_area)
        layout.addLayout(log_layout)

        self.setLayout(layout)

    def apply_dark_theme(self):
        dark_stylesheet = """
            QWidget {
                background-color: #121212;
                color: #ffffff;
                font-family: "Segoe UI", sans-serif;
                font-size: 14px;
            }
            QLabel {
                color: #ffffff;
            }
            QLineEdit, QTextEdit, QComboBox, QListWidget, QListWidgetItem, QSpinBox, QPushButton {
                background-color: #1E1E1E;
                border: 1px solid #555555;
                color: #ffffff;
                padding: 5px;
                border-radius: 4px;
            }
            QLineEdit:focus, QTextEdit:focus, QComboBox:focus, QListWidget:focus, QSpinBox:focus, QPushButton:focus {
                border: 2px solid #1E90FF;
            }
            QPushButton {
                background-color: #2D2D30;
            }
            QPushButton:hover {
                background-color: #3E3E42;
            }
            QPushButton:pressed {
                background-color: #5A5A5E;
            }
            QTabWidget::pane {
                border: 1px solid #555555;
            }
            QTabBar::tab {
                background: #2D2D30;
                border: 1px solid #555555;
                padding: 10px;
                margin: 2px;
                color: #ffffff;
                border-radius: 4px;
            }
            QTabBar::tab:selected {
                background: #1E90FF;
                color: #ffffff;
            }
            QListWidget::item:selected {
                background-color: #1E90FF;
                color: #ffffff;
            }
            QHeaderView::section {
                background-color: #2D2D30;
                color: #ffffff;
                padding: 4px;
                border: 1px solid #555555;
            }
            QDialog {
                background-color: #121212;
                color: #ffffff;
            }
            QDialog QPushButton {
                min-width: 80px;
            }
        """
        self.setStyleSheet(dark_stylesheet)

    def log_message(self, message):
        """Logs message to the text area."""
        self.log_area.append(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} - {message}")

# Client Management Tab
class ClientManagementTab(QWidget):
    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        self.init_ui()

    def init_ui(self):
        layout = QVBoxLayout()

        # Form to add/edit client
        form_group = QtWidgets.QGroupBox("Add New Client")
        form_layout = QHBoxLayout()
        self.client_name_input = QLineEdit(self)
        self.client_name_input.setPlaceholderText("Client Name")
        self.client_email_input = QLineEdit(self)
        self.client_email_input.setPlaceholderText("Client Email")
        self.client_address_input = QLineEdit(self)
        self.client_address_input.setPlaceholderText("Client Address")
        self.client_vat_input = QLineEdit(self)
        self.client_vat_input.setPlaceholderText("Client VAT Number")
        self.add_client_button = QPushButton("Add Client")
        self.add_client_button.clicked.connect(self.add_client)

        form_layout.addWidget(QLabel("Name:"))
        form_layout.addWidget(self.client_name_input)
        form_layout.addWidget(QLabel("Email:"))
        form_layout.addWidget(self.client_email_input)
        form_layout.addWidget(QLabel("Address:"))
        form_layout.addWidget(self.client_address_input)
        form_layout.addWidget(QLabel("VAT Number:"))
        form_layout.addWidget(self.client_vat_input)
        form_layout.addWidget(self.add_client_button)

        form_group.setLayout(form_layout)
        layout.addWidget(form_group)

        # List of clients
        self.clients_list = QListWidget()
        self.load_clients()
        layout.addWidget(QLabel("Existing Clients:"))
        layout.addWidget(self.clients_list)

        # Buttons to edit and delete clients
        btn_layout = QHBoxLayout()
        self.edit_client_button = QPushButton("Edit Selected")
        self.edit_client_button.clicked.connect(self.edit_client)
        self.delete_client_button = QPushButton("Delete Selected")
        self.delete_client_button.clicked.connect(self.delete_client)
        btn_layout.addWidget(self.edit_client_button)
        btn_layout.addWidget(self.delete_client_button)
        layout.addLayout(btn_layout)

        self.setLayout(layout)

    def load_clients(self):
        self.clients_list.clear()
        for client in self.parent.clients.keys():
            item = QListWidgetItem(client)
            self.clients_list.addItem(item)

    def add_client(self):
        name = self.client_name_input.text().strip()
        email = self.client_email_input.text().strip()
        address = self.client_address_input.text().strip()
        vat = self.client_vat_input.text().strip()

        if not name or not email or not address:
            QMessageBox.warning(self, "Input Error", "Please fill in all required fields.")
            return

        if name in self.parent.clients:
            QMessageBox.warning(self, "Duplicate Client", "Client already exists.")
            return

        self.parent.clients[name] = {
            "email": email,
            "address": address,
            "vat_number": vat
        }
        save_json(self.parent.clients, CLIENTS_FILE)
        self.parent.log_message(f"Client '{name}' added.")
        self.load_clients()
        self.client_name_input.clear()
        self.client_email_input.clear()
        self.client_address_input.clear()
        self.client_vat_input.clear()

    def edit_client(self):
        selected = self.clients_list.currentItem()
        if not selected:
            QMessageBox.warning(self, "Selection Error", "Please select a client to edit.")
            return
        name = selected.text()
        client_data = self.parent.clients[name]

        # Dialog to edit client
        dialog = EditClientDialog(name, client_data, self.parent)
        if dialog.exec():
            new_name, new_email, new_address, new_vat = dialog.get_data()
            if new_name != name and new_name in self.parent.clients:
                QMessageBox.warning(self, "Duplicate Client", "Client name already exists.")
                return
            # Update client
            del self.parent.clients[name]
            self.parent.clients[new_name] = {
                "email": new_email,
                "address": new_address,
                "vat_number": new_vat
            }
            save_json(self.parent.clients, CLIENTS_FILE)
            self.parent.log_message(f"Client '{name}' updated to '{new_name}'.")
            self.load_clients()

    def delete_client(self):
        selected = self.clients_list.currentItem()
        if not selected:
            QMessageBox.warning(self, "Selection Error", "Please select a client to delete.")
            return
        name = selected.text()
        reply = QMessageBox.question(
            self, 'Delete Confirmation',
            f"Are you sure you want to delete client '{name}'?",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
            QMessageBox.StandardButton.No
        )
        if reply == QMessageBox.StandardButton.Yes:
            del self.parent.clients[name]
            save_json(self.parent.clients, CLIENTS_FILE)
            self.parent.log_message(f"Client '{name}' deleted.")
            self.load_clients()

# Dialog for editing a client
class EditClientDialog(QDialog):
    def __init__(self, name, data, parent):
        super().__init__()
        self.setWindowTitle("Edit Client")
        self.parent = parent
        self.name = name
        self.data = data
        self.init_ui()

    def init_ui(self):
        self.layout = QVBoxLayout()

        self.name_input = QLineEdit(self)
        self.name_input.setText(self.name)
        self.email_input = QLineEdit(self)
        self.email_input.setText(self.data.get("email", ""))
        self.address_input = QLineEdit(self)
        self.address_input.setText(self.data.get("address", ""))
        self.vat_input = QLineEdit(self)
        self.vat_input.setText(self.data.get("vat_number", ""))

        self.layout.addWidget(QLabel("Name:"))
        self.layout.addWidget(self.name_input)
        self.layout.addWidget(QLabel("Email:"))
        self.layout.addWidget(self.email_input)
        self.layout.addWidget(QLabel("Address:"))
        self.layout.addWidget(self.address_input)
        self.layout.addWidget(QLabel("VAT Number:"))
        self.layout.addWidget(self.vat_input)

        self.button_box = QtWidgets.QDialogButtonBox(
            QtWidgets.QDialogButtonBox.StandardButton.Ok | QtWidgets.QDialogButtonBox.StandardButton.Cancel
        )
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)
        self.layout.addWidget(self.button_box)

        self.setLayout(self.layout)

    def get_data(self):
        return (
            self.name_input.text().strip(),
            self.email_input.text().strip(),
            self.address_input.text().strip(),
            self.vat_input.text().strip()
        )

# Line Item Management Tab
class LineItemManagementTab(QWidget):
    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        self.init_ui()

    def init_ui(self):
        layout = QVBoxLayout()

        # Form to add/edit line item
        form_group = QtWidgets.QGroupBox("Add New Line Item")
        form_layout = QHBoxLayout()
        self.item_name_input = QLineEdit(self)
        self.item_name_input.setPlaceholderText("Item Name")
        self.item_price_input = QLineEdit(self)
        self.item_price_input.setPlaceholderText("Item Price")
        self.add_item_button = QPushButton("Add Item")
        self.add_item_button.clicked.connect(self.add_line_item)

        form_layout.addWidget(QLabel("Name:"))
        form_layout.addWidget(self.item_name_input)
        form_layout.addWidget(QLabel("Price:"))
        form_layout.addWidget(self.item_price_input)
        form_layout.addWidget(self.add_item_button)

        form_group.setLayout(form_layout)
        layout.addWidget(form_group)

        # List of line items
        self.items_list = QListWidget()
        self.load_line_items()
        layout.addWidget(QLabel("Existing Line Items:"))
        layout.addWidget(self.items_list)

        # Buttons to edit, delete items
        btn_layout = QHBoxLayout()
        self.edit_item_button = QPushButton("Edit Selected")
        self.edit_item_button.clicked.connect(self.edit_line_item)
        self.delete_item_button = QPushButton("Delete Selected")
        self.delete_item_button.clicked.connect(self.delete_line_item)
        btn_layout.addWidget(self.edit_item_button)
        btn_layout.addWidget(self.delete_item_button)
        layout.addLayout(btn_layout)

        self.setLayout(layout)

    def load_line_items(self):
        self.items_list.clear()
        for item, details in self.parent.line_items_data.items():
            price = details.get('price', 0.0)
            self.items_list.addItem(f"{item} - Price: ${price:.2f}")

    def add_line_item(self):
        name = self.item_name_input.text().strip()
        price = self.item_price_input.text().strip()

        if not name or not price:
            QMessageBox.warning(self, "Input Error", "Please fill in the Item Name and Price.")
            return

        try:
            price = float(price)
            if price < 0:
                raise ValueError
        except ValueError:
            QMessageBox.warning(self, "Input Error", "Please enter a valid positive price.")
            return

        if name in self.parent.line_items_data:
            QMessageBox.warning(self, "Duplicate Item", "Line item already exists.")
            return

        self.parent.line_items_data[name] = {"price": price}
        save_json(self.parent.line_items_data, LINE_ITEMS_FILE)
        self.parent.log_message(f"Line item '{name}' added.")
        self.load_line_items()
        self.item_name_input.clear()
        self.item_price_input.clear()

    def edit_line_item(self):
        selected = self.items_list.currentItem()
        if not selected:
            QMessageBox.warning(self, "Selection Error", "Please select a line item to edit.")
            return
        item_text = selected.text()
        name = item_text.split(" - Price: ")[0]
        item_data = self.parent.line_items_data[name]

        # Dialog to edit line item
        dialog = EditLineItemDialog(name, item_data, self.parent)
        if dialog.exec():
            new_name, new_price = dialog.get_data()
            if new_name != name and new_name in self.parent.line_items_data:
                QMessageBox.warning(self, "Duplicate Item", "Line item name already exists.")
                return
            try:
                new_price = float(new_price)
                if new_price < 0:
                    raise ValueError
            except ValueError:
                QMessageBox.warning(self, "Input Error", "Please enter a valid positive price.")
                return
            # Update line item
            del self.parent.line_items_data[name]
            self.parent.line_items_data[new_name] = {"price": new_price}
            save_json(self.parent.line_items_data, LINE_ITEMS_FILE)
            self.parent.log_message(f"Line item '{name}' updated to '{new_name}'.")
            self.load_line_items()

    def delete_line_item(self):
        selected = self.items_list.currentItem()
        if not selected:
            QMessageBox.warning(self, "Selection Error", "Please select a line item to delete.")
            return
        item_text = selected.text()
        name = item_text.split(" - Price: ")[0]
        reply = QMessageBox.question(
            self, 'Delete Confirmation',
            f"Are you sure you want to delete line item '{name}'?",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
            QMessageBox.StandardButton.No
        )
        if reply == QMessageBox.StandardButton.Yes:
            del self.parent.line_items_data[name]
            save_json(self.parent.line_items_data, LINE_ITEMS_FILE)
            self.parent.log_message(f"Line item '{name}' deleted.")
            self.load_line_items()

# Dialog for editing a line item
class EditLineItemDialog(QDialog):
    def __init__(self, name, data, parent):
        super().__init__()
        self.setWindowTitle("Edit Line Item")
        self.parent = parent
        self.name = name
        self.data = data
        self.init_ui()

    def init_ui(self):
        self.layout = QVBoxLayout()

        self.name_input = QLineEdit(self)
        self.name_input.setText(self.name)
        self.price_input = QLineEdit(self)
        self.price_input.setText(str(self.data["price"]))

        self.layout.addWidget(QLabel("Name:"))
        self.layout.addWidget(self.name_input)
        self.layout.addWidget(QLabel("Price:"))
        self.layout.addWidget(self.price_input)

        self.button_box = QtWidgets.QDialogButtonBox(
            QtWidgets.QDialogButtonBox.StandardButton.Ok | QtWidgets.QDialogButtonBox.StandardButton.Cancel
        )
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)
        self.layout.addWidget(self.button_box)

        self.setLayout(self.layout)

    def get_data(self):
        return (
            self.name_input.text().strip(),
            self.price_input.text().strip()
        )

# Invoice Creation Tab
class InvoiceCreationTab(QWidget):
    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        self.line_items = []
        self.init_ui()

    def init_ui(self):
        layout = QVBoxLayout()

        # Client selection
        client_layout = QHBoxLayout()
        self.client_combo = QComboBox(self)
        self.load_clients()
        client_layout.addWidget(QLabel("Select Client:"))
        client_layout.addWidget(self.client_combo)
        layout.addLayout(client_layout)

        # VAT Number Display (Read-only)
        vat_display_layout = QHBoxLayout()
        self.vat_display = QLineEdit(self)
        self.vat_display.setReadOnly(True)
        vat_display_layout.addWidget(QLabel("Client VAT Number:"))
        vat_display_layout.addWidget(self.vat_display)
        layout.addLayout(vat_display_layout)

        # Update VAT display when client changes
        self.client_combo.currentIndexChanged.connect(self.update_vat_display)
        self.update_vat_display()

        # Line Items selection
        line_item_layout = QHBoxLayout()
        self.item_combo = QComboBox(self)
        self.load_line_items()
        self.quantity_input = QSpinBox(self)
        self.quantity_input.setMinimum(1)
        self.quantity_input.setValue(1)
        self.add_item_button = QPushButton("Add Item")
        self.add_item_button.clicked.connect(self.add_line_item)
        line_item_layout.addWidget(QLabel("Item:"))
        line_item_layout.addWidget(self.item_combo)
        line_item_layout.addWidget(QLabel("Quantity:"))
        line_item_layout.addWidget(self.quantity_input)
        line_item_layout.addWidget(self.add_item_button)
        layout.addLayout(line_item_layout)

        # List to display added line items
        self.added_items_list = QListWidget()
        self.added_items_list.setStyleSheet("""
            QListWidget {
                background-color: #1E1E1E;
                color: #ffffff;
                border: 1px solid #555555;
            }
            QListWidget::item {
                padding: 5px;
            }
        """)
        layout.addWidget(QLabel("Added Line Items:"))
        layout.addWidget(self.added_items_list)

        # Discounts and Taxes
        discounts_taxes_layout = QHBoxLayout()
        self.discount_input = QLineEdit(self)
        self.discount_input.setPlaceholderText("Discount (%)")
        self.tax_rate_input = QLineEdit(self)
        self.tax_rate_input.setPlaceholderText("Tax Rate (%)")
        discounts_taxes_layout.addWidget(QLabel("Discount (%):"))
        discounts_taxes_layout.addWidget(self.discount_input)
        discounts_taxes_layout.addWidget(QLabel("Tax Rate (%):"))
        discounts_taxes_layout.addWidget(self.tax_rate_input)
        layout.addLayout(discounts_taxes_layout)

        # Output Format Selection
        output_layout = QHBoxLayout()
        self.output_format_combo = QComboBox(self)
        self.output_format_combo.addItems(["PDF", "Excel"])
        output_layout.addWidget(QLabel("Output Format:"))
        output_layout.addWidget(self.output_format_combo)
        layout.addLayout(output_layout)

        # Button to create invoice
        self.create_invoice_button = QPushButton("Create Invoice")
        self.create_invoice_button.clicked.connect(self.create_invoice)
        layout.addWidget(self.create_invoice_button)

        self.setLayout(layout)

    def load_clients(self):
        self.client_combo.clear()
        self.client_combo.addItems(list(self.parent.clients.keys()))

    def load_line_items(self):
        self.item_combo.clear()
        self.item_combo.addItems(list(self.parent.line_items_data.keys()))

    def add_line_item(self):
        item_name = self.item_combo.currentText()
        quantity = self.quantity_input.value()
        if not item_name:
            QMessageBox.warning(self, "Selection Error", "Please select a line item.")
            return
        price = self.parent.line_items_data[item_name]['price']
        total = price * quantity
        self.line_items.append({
            "item": item_name,
            "quantity": quantity,
            "price": price,
            "total": total
        })
        self.update_added_items_list()

    def update_added_items_list(self):
        self.added_items_list.clear()
        for idx, item in enumerate(self.line_items, 1):
            self.added_items_list.addItem(
                f"{idx}. {item['item']} - Qty: {item['quantity']} - Price: ${item['price']:.2f} - Total: ${item['total']:.2f}"
            )

    def update_vat_display(self):
        client_name = self.client_combo.currentText()
        vat_number = self.parent.clients.get(client_name, {}).get("vat_number", "")
        self.vat_display.setText(vat_number)

    def create_invoice(self):
        client_name = self.client_combo.currentText()
        vat_number = self.parent.clients.get(client_name, {}).get("vat_number", "")
        discount = self.discount_input.text().strip()
        tax_rate = self.tax_rate_input.text().strip()

        if not client_name:
            QMessageBox.warning(self, "Input Error", "Please select a client.")
            return

        if not self.line_items:
            QMessageBox.warning(self, "Input Error", "Please add at least one line item.")
            return

        # Calculate totals
        subtotal = sum(item['total'] for item in self.line_items)
        discount_amount = 0
        if discount:
            try:
                discount_percentage = float(discount)
                discount_amount = subtotal * (discount_percentage / 100)
            except ValueError:
                QMessageBox.warning(self, "Input Error", "Please enter a valid discount percentage.")
                return

        subtotal_after_discount = subtotal - discount_amount

        tax_amount = 0
        if tax_rate:
            try:
                tax_percentage = float(tax_rate)
                tax_amount = subtotal_after_discount * (tax_percentage / 100)
            except ValueError:
                QMessageBox.warning(self, "Input Error", "Please enter a valid tax rate percentage.")
                return

        total = subtotal_after_discount + tax_amount

        invoice_date = datetime.now().strftime("%Y-%m-%d")
        client_address = self.parent.clients[client_name]["address"]
        invoice_filename = f"{client_name.replace(' ', '_')}_invoice_{self.parent.invoice_counter}"

        # Prepare DataFrame
        df = pd.DataFrame([
            {"Item": item['item'], "Quantity": item['quantity'], "Price": item['price'], "Total": item['total']}
            for item in self.line_items
        ])

        output_format = self.output_format_combo.currentText()
        success = False
        if output_format == "PDF":
            success = self.create_pdf(client_name, vat_number, invoice_date, client_address, df, invoice_filename, subtotal, discount_amount, tax_amount, total)
        elif output_format == "Excel":
            success = self.create_excel(client_name, vat_number, invoice_date, client_address, df, invoice_filename, subtotal, discount_amount, tax_amount, total)
        else:
            QMessageBox.warning(self, "Format Error", "Please select a valid output format.")
            return

        if success:
            # Log invoice metadata
            invoice_number = self.parent.invoice_counter - 1
            invoice_metadata = {
                "invoice_number": invoice_number,
                "client_name": client_name,
                "date": invoice_date,
                "total": total,
                "status": "Unpaid",
                "filename": f"{invoice_filename}.{output_format.lower()}"
            }
            self.parent.invoices_metadata[str(invoice_number)] = invoice_metadata
            save_json(self.parent.invoices_metadata, INVOICES_METADATA_FILE)
            QMessageBox.information(self, "Success", f"Invoice '{invoice_filename}' created successfully.")
            # Reset form
            self.line_items = []
            self.update_added_items_list()
            self.parent.invoice_counter += 1
            self.parent.update_invoice_counter()

    def create_pdf(self, client, vat, invoice_date, client_address, df, invoice_filename, subtotal, discount, tax, total):
        """Generate PDF invoice."""
        try:
            pdf_filename = os.path.join(INVOICES_DIR, f"{invoice_filename}.pdf")

            c = canvas.Canvas(pdf_filename, pagesize=letter)
            width, height = letter

            # Company Details
            company_name = self.parent.company_details.get("company_name", "Your Company Name")
            company_address = self.parent.company_details.get("company_address", "Your Company Address")
            company_email = self.parent.company_details.get("company_email", "your.email@example.com")
            company_phone = self.parent.company_details.get("company_phone", "123-456-7890")

            # Invoice Header
            c.setFont("Helvetica-Bold", 20)
            c.drawString(50, height - 50, "INVOICE")

            # Company Info
            c.setFont("Helvetica-Bold", 12)
            c.drawString(50, height - 80, company_name)
            c.setFont("Helvetica", 10)
            c.drawString(50, height - 95, company_address)
            c.drawString(50, height - 110, f"Email: {company_email}")
            c.drawString(50, height - 125, f"Phone: {company_phone}")

            # Invoice Info
            c.drawString(400, height - 80, f"Invoice Number: {self.parent.invoice_counter - 1}")
            c.drawString(400, height - 95, f"Date: {invoice_date}")

            # Client Info
            c.setFont("Helvetica-Bold", 12)
            c.drawString(50, height - 160, "Bill To:")
            c.setFont("Helvetica", 10)
            c.drawString(50, height - 175, client)
            c.drawString(50, height - 190, client_address)
            if vat:
                c.drawString(50, height - 205, f"VAT Number: {vat}")

            # Table Headers
            c.setFont("Helvetica-Bold", 10)
            c.drawString(50, height - 230, "Item")
            c.drawString(250, height - 230, "Quantity")
            c.drawString(350, height - 230, "Price")
            c.drawString(450, height - 230, "Total")

            # Table Content
            y = height - 245
            c.setFont("Helvetica", 10)
            for index, row in df.iterrows():
                c.drawString(50, y, str(row['Item']))
                c.drawString(250, y, str(row['Quantity']))
                c.drawString(350, y, f"${row['Price']:.2f}")
                c.drawString(450, y, f"${row['Total']:.2f}")
                y -= 15
                if y < 50:
                    c.showPage()
                    y = height - 50

            # Totals
            c.setFont("Helvetica-Bold", 10)
            c.drawString(350, y - 10, "Subtotal:")
            c.drawString(450, y - 10, f"${subtotal:.2f}")
            y -= 15
            if discount > 0:
                c.drawString(350, y - 10, "Discount:")
                c.drawString(450, y - 10, f"-${discount:.2f}")
                y -= 15
            if tax > 0:
                c.drawString(350, y - 10, "Tax:")
                c.drawString(450, y - 10, f"${tax:.2f}")
                y -= 15
            c.drawString(350, y - 10, "Total:")
            c.drawString(450, y - 10, f"${total:.2f}")

            c.save()
            self.parent.log_message(f"Invoice saved as {pdf_filename}")
            self.parent.manage_invoices_tab.load_invoices()
            self.parent.financial_statements_tab.load_financial_statements()
            return True
        except Exception as e:
            QMessageBox.warning(self, "PDF Generation Error", f"Failed to generate PDF invoice: {e}")
            self.parent.log_message(f"Failed to generate PDF invoice '{invoice_filename}': {e}")
            return False

    def create_excel(self, client, vat, invoice_date, client_address, df, invoice_filename, subtotal, discount, tax, total):
        """Generate Excel invoice."""
        try:
            excel_filename = os.path.join(INVOICES_DIR, f"{invoice_filename}.xlsx")

            writer = pd.ExcelWriter(excel_filename, engine='openpyxl')
            df.to_excel(writer, index=False, sheet_name='Invoice')
            workbook = writer.book
            worksheet = writer.sheets['Invoice']

            # Company Details
            company_name = self.parent.company_details.get("company_name", "Your Company Name")
            company_address = self.parent.company_details.get("company_address", "Your Company Address")
            company_email = self.parent.company_details.get("company_email", "your.email@example.com")
            company_phone = self.parent.company_details.get("company_phone", "123-456-7890")

            # Write header
            worksheet['A1'] = "INVOICE"
            worksheet['A1'].font = worksheet['A1'].font.copy(bold=True, size=20)

            worksheet['A3'] = company_name
            worksheet['A4'] = company_address
            worksheet['A5'] = f"Email: {company_email}"
            worksheet['A6'] = f"Phone: {company_phone}"

            worksheet['D3'] = f"Invoice Number: {self.parent.invoice_counter - 1}"
            worksheet['D4'] = f"Date: {invoice_date}"

            # Client Info
            worksheet['A8'] = "Bill To:"
            worksheet['A9'] = client
            worksheet['A10'] = client_address
            if vat:
                worksheet['A11'] = f"VAT Number: {vat}"

            # Adjust column widths
            worksheet.column_dimensions['A'].width = 30
            worksheet.column_dimensions['B'].width = 15
            worksheet.column_dimensions['C'].width = 15
            worksheet.column_dimensions['D'].width = 15

            # Add totals
            current_row = len(df) + 15
            worksheet[f'C{current_row}'] = "Subtotal:"
            worksheet[f'D{current_row}'] = subtotal
            if discount > 0:
                current_row += 1
                worksheet[f'C{current_row}'] = "Discount:"
                worksheet[f'D{current_row}'] = -discount
            if tax > 0:
                current_row += 1
                worksheet[f'C{current_row}'] = "Tax:"
                worksheet[f'D{current_row}'] = tax
            current_row += 1
            worksheet[f'C{current_row}'] = "Total:"
            worksheet[f'D{current_row}'] = total

            writer.save()
            self.parent.log_message(f"Invoice saved as {excel_filename}")
            self.parent.manage_invoices_tab.load_invoices()
            self.parent.financial_statements_tab.load_financial_statements()
            return True
        except Exception as e:
            QMessageBox.warning(self, "Excel Generation Error", f"Failed to generate Excel invoice: {e}")
            self.parent.log_message(f"Failed to generate Excel invoice '{invoice_filename}': {e}")
            return False

# Manage Invoices Tab
class ManageInvoicesTab(QWidget):
    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        self.init_ui()

    def init_ui(self):
        layout = QVBoxLayout()

        # List of invoices
        self.invoices_list = QListWidget()
        self.invoices_list.setStyleSheet("""
            QListWidget {
                background-color: #1E1E1E;
                color: #ffffff;
                border: 1px solid #555555;
            }
            QListWidget::item {
                padding: 5px;
            }
        """)
        self.load_invoices()
        layout.addWidget(QLabel("Invoices:"))
        layout.addWidget(self.invoices_list)

        # Buttons to view and delete invoices
        btn_layout = QHBoxLayout()
        self.view_invoice_button = QPushButton("View Invoice")
        self.view_invoice_button.clicked.connect(self.view_invoice)
        self.delete_invoice_button = QPushButton("Delete Invoice")
        self.delete_invoice_button.clicked.connect(self.delete_invoice)
        btn_layout.addWidget(self.view_invoice_button)
        btn_layout.addWidget(self.delete_invoice_button)
        layout.addLayout(btn_layout)

        self.setLayout(layout)

    def load_invoices(self):
        self.invoices_list.clear()
        if not os.path.exists(INVOICES_DIR):
            return
        invoices = sorted(os.listdir(INVOICES_DIR), reverse=True)
        for invoice in invoices:
            item = QListWidgetItem(invoice)
            self.invoices_list.addItem(item)

    def get_selected_invoice_path(self):
        selected = self.invoices_list.currentItem()
        if not selected:
            QMessageBox.warning(self, "Selection Error", "Please select an invoice.")
            return None
        invoice_filename = selected.text()
        invoice_path = os.path.join(INVOICES_DIR, invoice_filename)
        return invoice_path

    def view_invoice(self):
        invoice_path = self.get_selected_invoice_path()
        if not invoice_path:
            return
        if not os.path.exists(invoice_path):
            QMessageBox.warning(self, "File Not Found", "The selected invoice file does not exist.")
            return
        QtGui.QDesktopServices.openUrl(QtCore.QUrl.fromLocalFile(os.path.abspath(invoice_path)))

    def delete_invoice(self):
        invoice_path = self.get_selected_invoice_path()
        if not invoice_path:
            return
        reply = QMessageBox.question(
            self, 'Delete Confirmation',
            f"Are you sure you want to delete invoice '{os.path.basename(invoice_path)}'?",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
            QMessageBox.StandardButton.No
        )
        if reply == QMessageBox.StandardButton.Yes:
            try:
                invoice_filename = os.path.basename(invoice_path)
                parts = invoice_filename.split('_invoice_')
                if len(parts) < 2:
                    raise ValueError("Invalid invoice filename format.")
                invoice_number_part = parts[1].split('.')[0]
                invoice_number = str(int(invoice_number_part))
                if invoice_number in self.parent.invoices_metadata:
                    del self.parent.invoices_metadata[invoice_number]
                    save_json(self.parent.invoices_metadata, INVOICES_METADATA_FILE)

                os.remove(invoice_path)
                self.parent.log_message(f"Invoice '{os.path.basename(invoice_path)}' deleted.")
                self.load_invoices()
                self.parent.financial_statements_tab.load_financial_statements()
            except Exception as e:
                QMessageBox.warning(self, "Delete Error", f"Failed to delete invoice: {e}")
                self.parent.log_message(f"Failed to delete invoice '{invoice_path}': {e}")

# Financial Statements Tab
class FinancialStatementsTab(QWidget):
    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        self.init_ui()

    def init_ui(self):
        layout = QVBoxLayout()

        # Client Selection
        client_layout = QHBoxLayout()
        self.client_combo = QComboBox(self)
        self.load_clients()
        client_layout.addWidget(QLabel("Select Client:"))
        client_layout.addWidget(self.client_combo)
        layout.addLayout(client_layout)

        # Financial Statements Table
        self.financial_table = QTableWidget()
        self.financial_table.setColumnCount(5)
        self.financial_table.setHorizontalHeaderLabels(["Invoice Number", "Date", "Total", "Status", "Filename"])
        self.financial_table.horizontalHeader().setStretchLastSection(True)
        self.financial_table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
        self.financial_table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
        layout.addWidget(QLabel("Financial Statements:"))
        layout.addWidget(self.financial_table)

        # Load financial statements when client is selected
        self.client_combo.currentIndexChanged.connect(self.load_financial_statements)
        self.load_financial_statements()

        self.setLayout(layout)

    def load_clients(self):
        self.client_combo.clear()
        self.client_combo.addItems(list(self.parent.clients.keys()))

    def load_financial_statements(self):
        client_name = self.client_combo.currentText()
        if not client_name:
            return

        # Clear existing table
        self.financial_table.setRowCount(0)
        total_invoiced = 0.0

        # Iterate through invoice metadata and populate table
        for invoice_number, metadata in self.parent.invoices_metadata.items():
            if metadata["client_name"] != client_name:
                continue
            invoice_number_display = metadata.get("invoice_number", "N/A")
            invoice_date = metadata.get("date", "N/A")
            total = metadata.get("total", 0.0)
            status = metadata.get("status", "Unpaid")
            filename = metadata.get("filename", "N/A")

            total_invoiced += total

            # Add row to table
            row_position = self.financial_table.rowCount()
            self.financial_table.insertRow(row_position)
            self.financial_table.setItem(row_position, 0, QtWidgets.QTableWidgetItem(str(invoice_number_display)))
            self.financial_table.setItem(row_position, 1, QtWidgets.QTableWidgetItem(invoice_date))
            self.financial_table.setItem(row_position, 2, QtWidgets.QTableWidgetItem(f"${total:.2f}"))
            self.financial_table.setItem(row_position, 3, QtWidgets.QTableWidgetItem(status))
            self.financial_table.setItem(row_position, 4, QtWidgets.QTableWidgetItem(filename))

        # Display total invoiced amount
        self.parent.log_message(f"Total invoiced amount for {client_name}: ${total_invoiced:.2f}")

# Company Details Tab
class CompanyDetailsTab(QWidget):
    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        self.init_ui()

    def init_ui(self):
        layout = QVBoxLayout()

        # Company details form
        form_group = QtWidgets.QGroupBox("Company Details")
        form_layout = QVBoxLayout()
        self.company_name_input = QLineEdit(self)
        self.company_name_input.setPlaceholderText("Company Name")
        self.company_address_input = QLineEdit(self)
        self.company_address_input.setPlaceholderText("Company Address")
        self.company_email_input = QLineEdit(self)
        self.company_email_input.setPlaceholderText("Company Email")
        self.company_phone_input = QLineEdit(self)
        self.company_phone_input.setPlaceholderText("Company Phone")

        form_layout.addWidget(QLabel("Company Name:"))
        form_layout.addWidget(self.company_name_input)
        form_layout.addWidget(QLabel("Company Address:"))
        form_layout.addWidget(self.company_address_input)
        form_layout.addWidget(QLabel("Company Email:"))
        form_layout.addWidget(self.company_email_input)
        form_layout.addWidget(QLabel("Company Phone:"))
        form_layout.addWidget(self.company_phone_input)

        form_group.setLayout(form_layout)
        layout.addWidget(form_group)

        # Save button
        self.save_company_details_button = QPushButton("Save Company Details")
        self.save_company_details_button.clicked.connect(self.save_company_details)
        layout.addWidget(self.save_company_details_button)

        self.setLayout(layout)
        self.load_existing_details()

    def load_existing_details(self):
        details = self.parent.company_details
        if details:
            self.company_name_input.setText(details.get("company_name", ""))
            self.company_address_input.setText(details.get("company_address", ""))
            self.company_email_input.setText(details.get("company_email", ""))
            self.company_phone_input.setText(details.get("company_phone", ""))

    def save_company_details(self):
        company_name = self.company_name_input.text().strip()
        company_address = self.company_address_input.text().strip()
        company_email = self.company_email_input.text().strip()
        company_phone = self.company_phone_input.text().strip()

        if not company_name or not company_address or not company_email or not company_phone:
            QMessageBox.warning(self, "Input Error", "Please fill in all required fields.")
            return

        self.parent.company_details = {
            "company_name": company_name,
            "company_address": company_address,
            "company_email": company_email,
            "company_phone": company_phone
        }
        save_json(self.parent.company_details, COMPANY_DETAILS_FILE)
        self.parent.log_message("Company details updated.")
        QMessageBox.information(self, "Success", "Company details have been saved.")

# Run the application
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = InvoiceApp()
    window.show()
    sys.exit(app.exec())