Upgrade and revise this script so that the financial statements tab is actually functional and ensure that the VAT under the invoice creation tab automatically pulls the client's VAT number. Add more lines/boxes around text to the invoice layout for a more professional look.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 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, QColorDialog, QFontDialog
)

# Define file paths
CLIENTS_FILE = 'clients.json'
LINE_ITEMS_FILE = 'line_items.json'
INVOICES_DIR = 'invoices'
EMAIL_CONFIG_FILE = 'email_config.json'
TEMPLATES_FILE = 'templates.json'
COMPANY_DETAILS_FILE = 'company_details.json'  # New file for company details

# 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):
        with open(file_path, 'r') as f:
            return json.load(f)
    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)

# Load initial data
clients = load_json(CLIENTS_FILE)
line_items_data = load_json(LINE_ITEMS_FILE)
email_config = load_json(EMAIL_CONFIG_FILE)
templates = load_json(TEMPLATES_FILE)
company_details = load_json(COMPANY_DETAILS_FILE)  # Load company details

# GUI Application
class QuickBooksReplacement(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.clients = load_json(CLIENTS_FILE)
        self.line_items_data = load_json(LINE_ITEMS_FILE)
        self.email_config = load_json(EMAIL_CONFIG_FILE)
        self.templates = load_json(TEMPLATES_FILE)
        self.company_details = load_json(COMPANY_DETAILS_FILE)  # Initialize company details
        self.invoice_counter = self.get_next_invoice_number()  # Initialize invoice counter
        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("QuickBooks Replacement Tool")
        self.setGeometry(100, 100, 1200, 800)  # Increased width and height for better layout
        layout = QVBoxLayout()

        # Apply Enhanced 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)  # New Financial Statements Tab
        self.email_config_tab = EmailConfigTab(self)
        self.company_details_tab = CompanyDetailsTab(self)  # New Company Details Tab
        self.templates_tab = TemplateManagementTab(self)  # Templates Tab

        self.tabs.addTab(self.client_tab, QtGui.QIcon.fromTheme("user-group"), "Clients")
        self.tabs.addTab(self.line_item_tab, QtGui.QIcon.fromTheme("list-add"), "Line Items")
        self.tabs.addTab(self.invoice_tab, QtGui.QIcon.fromTheme("document-new"), "Create Invoice")
        self.tabs.addTab(self.manage_invoices_tab, QtGui.QIcon.fromTheme("folder"), "Manage Invoices")
        self.tabs.addTab(self.financial_statements_tab, QtGui.QIcon.fromTheme("view-summary"), "Financial Statements")  # New Tab
        self.tabs.addTab(self.email_config_tab, QtGui.QIcon.fromTheme("email-send"), "Email Settings")
        self.tabs.addTab(self.company_details_tab, QtGui.QIcon.fromTheme("office-address"), "Company Details")  # New Tab
        self.tabs.addTab(self.templates_tab, QtGui.QIcon.fromTheme("format-paint"), "Templates")

        # 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 = """
            /* General Widget Styles */
            QWidget {
                background-color: #121212;
                color: #ffffff;
                font-family: "Segoe UI", sans-serif;
                font-size: 14px;
            }
            QLabel {
                color: #ffffff;
            }
            QLineEdit, QTextEdit, QComboBox, QListWidget, 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;
            }
            QMenuBar, QMenu {
                background-color: #121212;
                color: #ffffff;
                font-size: 14px;
            }
            QMenu::item:selected {
                background-color: #3E3E42;
            }
            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}")

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)  # New VAT Number Field
        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:"))  # Label for VAT
        form_layout.addWidget(self.client_vat_input)    # 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()  # Retrieve VAT number

        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  # Store VAT number
        }
        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  # Update VAT number
            }
            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()

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)  # VAT Number Field
        self.vat_input.setText(self.data.get("vat_number", ""))  # Retrieve 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:"))  # Label for VAT
        self.layout.addWidget(self.vat_input)          # 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()  # Return VAT number
        )

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 and 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 in self.parent.line_items_data.keys():
            item_obj = QListWidgetItem(item)
            self.items_list.addItem(item_obj)

    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 all fields.")
            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
        name = selected.text()
        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
        name = selected.text()
        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()

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()
        )

class InvoiceCreationTab(QWidget):
    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        self.line_items = []
        self.selected_template = None  # For template usage
        self.init_ui()

    def init_ui(self):
        layout = QVBoxLayout()

        # Template Selection
        template_layout = QHBoxLayout()
        self.template_combo = QComboBox(self)
        self.load_templates()
        self.template_combo.currentIndexChanged.connect(self.change_template)
        template_layout.addWidget(QLabel("Select Template:"))
        template_layout.addWidget(self.template_combo)
        layout.addLayout(template_layout)

        # 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)

        # Remove VAT Number input as it is now auto-filled from client data
        # If necessary, display VAT number as 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)

        # 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_templates(self):
        self.template_combo.clear()
        templates_list = list(self.parent.templates.keys())
        self.template_combo.addItems(["Default"] + templates_list)
        self.selected_template = "Default"

    def change_template(self, index):
        selected = self.template_combo.currentText()
        if selected == "Default":
            self.selected_template = None
        else:
            self.selected_template = selected

    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: R{item['price']:.2f} - Total: R{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")  # Automatic date filling
        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 (ZAR)": item['price'], "Total (ZAR)": item['total']}
            for item in self.line_items
        ])

        output_format = self.output_format_combo.currentText()
        if output_format == "PDF":
            self.create_pdf(client_name, vat_number, invoice_date, client_address, df, invoice_filename, subtotal, discount_amount, tax_amount, total)
        elif output_format == "Excel":
            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.")

        # Reset form
        self.line_items = []
        self.update_added_items_list()
        self.parent.invoice_counter += 1  # Increment invoice counter after successful creation
        self.parent.update_invoice_counter()

    def apply_template_attributes(self, c, template, invoice_details):
        """Applies template attributes like header, footer, and logo to the PDF."""
        if 'header_text' in template:
            c.setFont("Helvetica-Bold", 16)
            c.drawString(50, invoice_details['height'] - 50, template['header_text'])

        if 'footer_text' in template:
            c.setFont("Helvetica", 10)
            c.drawString(50, 50, template['footer_text'])

        if 'logo_path' in template and template['logo_path']:
            if os.path.exists(template['logo_path']):
                c.drawImage(template['logo_path'], invoice_details['width'] - 150, invoice_details['height'] - 100, width=100, height=50)

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

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

        # Apply Template Attributes
        invoice_details = {'width': width, 'height': height}
        self.apply_template_attributes(c, template, invoice_details)

        # 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")
        # Optional: Company logo
        if self.parent.company_details.get("company_logo_path", "") and os.path.exists(self.parent.company_details["company_logo_path"]):
            c.drawImage(self.parent.company_details["company_logo_path"], 50, height - 100, width=100, height=50)

        c.setFont("Helvetica-Bold", 14)
        c.drawString(50, height - 120, company_name)
        c.setFont("Helvetica", 12)
        c.drawString(50, height - 140, company_address)
        c.drawString(50, height - 160, f"Email: {company_email}")
        c.drawString(50, height - 180, f"Phone: {company_phone}")

        # Invoice Header
        c.setFont("Helvetica-Bold", 20)
        c.drawString(400, height - 120, "INVOICE")  # Adjusted position

        # Invoice Information
        c.setFont("Helvetica", 12)
        c.drawString(400, height - 150, f"Invoice Number: {self.parent.invoice_counter - 1}")  # Displaying counter
        c.drawString(400, height - 170, f"Date: {invoice_date}")

        # Client Information
        c.setFont("Helvetica-Bold", 12)
        c.drawString(50, height - 220, "Bill To:")
        c.setFont("Helvetica", 12)
        c.drawString(50, height - 240, f"{client}")
        c.drawString(50, height - 260, f"Address: {client_address}")
        if vat:
            c.drawString(50, height - 280, f"VAT Number: {vat}")

        # Table Headers
        c.setFont("Helvetica-Bold", 12)
        y = height - 320
        c.drawString(50, y, "Item")
        c.drawString(250, y, "Quantity")
        c.drawString(350, y, "Price (ZAR)")
        c.drawString(450, y, "Total (ZAR)")
        y -= 20
        c.line(50, y, 550, y)

        # Table Content
        c.setFont("Helvetica", 12)
        for index, row in df.iterrows():
            y -= 20
            if y < 150:
                c.showPage()
                y = height - 50
                # Re-apply template on new page
                self.apply_template_attributes(c, template, invoice_details)
            c.drawString(50, y, str(row['Item']))
            c.drawString(250, y, str(row['Quantity']))
            c.drawString(350, y, f"R{row['Price (ZAR)']:.2f}")
            c.drawString(450, y, f"R{row['Total (ZAR)']:.2f}")

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

        # Footnote
        c.setFont("Helvetica-Oblique", 10)
        c.drawString(50, 30, "Thank you for your business.")  # Added footnote

        c.save()
        self.parent.log_message(f"Invoice saved as {pdf_filename}")
        self.parent.manage_invoices_tab.load_invoices()
        self.send_email_invoice(client, pdf_filename)

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

        writer = pd.ExcelWriter(excel_filename, engine='openpyxl')
        df.to_excel(writer, index=False, sheet_name='Invoice')

        # Access the workbook and worksheet
        workbook = writer.book
        worksheet = writer.sheets['Invoice']

        # Apply Template Attributes (basic - headers)
        current_row = 1
        if 'header_text' in template:
            worksheet.merge_cells(start_row=current_row, start_column=1, end_row=current_row, end_column=4)
            cell = worksheet.cell(row=current_row, column=1)
            cell.value = template['header_text']
            cell.font = cell.font.copy(bold=True, size=16)
            current_row += 1

        # 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")
        company_logo = self.parent.company_details.get("company_logo_path", "")

        if company_logo and os.path.exists(company_logo):
            # Insert company logo if available
            img = openpyxl.drawing.image.Image(company_logo)
            img.anchor = 'A1'
            worksheet.add_image(img, 'A1')
            current_row += 2  # Adjust row if logo is added

        worksheet.cell(row=current_row, column=1, value=company_name)
        worksheet.cell(row=current_row, column=2, value=f"Invoice Number: {self.parent.invoice_counter - 1}")
        current_row += 1
        worksheet.cell(row=current_row, column=1, value=company_address)
        worksheet.cell(row=current_row, column=2, value=f"Date: {invoice_date}")
        current_row += 1
        worksheet.cell(row=current_row, column=1, value=f"Email: {company_email}")
        worksheet.cell(row=current_row, column=2, value=f"Client: {client}")
        current_row += 1
        worksheet.cell(row=current_row, column=1, value=f"Phone: {company_phone}")
        worksheet.cell(row=current_row, column=2, value=f"Address: {client_address}")
        current_row += 1
        if vat:
            worksheet.cell(row=current_row, column=1, value=f"VAT Number: {vat}")
            current_row += 1

        # Add totals
        start_row = len(df) + current_row + 2
        worksheet.cell(row=start_row, column=3, value="Subtotal:")
        worksheet.cell(row=start_row, column=4, value=subtotal)
        if discount > 0:
            worksheet.cell(row=start_row + 1, column=3, value="Discount:")
            worksheet.cell(row=start_row + 1, column=4, value=-discount)
        if tax > 0:
            worksheet.cell(row=start_row + 2, column=3, value="Tax:")
            worksheet.cell(row=start_row + 2, column=4, value=tax)
        worksheet.cell(row=start_row + 3, column=3, value="Total:")
        worksheet.cell(row=start_row + 3, column=4, value=total)

        # Add footnote
        worksheet.cell(row=start_row + 5, column=1, value="Thank you for your business.")

        # Apply Template Styles (basic)
        for row in worksheet.iter_rows(min_row=1, max_row=start_row + 5, min_col=1, max_col=4):
            for cell in row:
                cell.font = cell.font.copy(color="FFFFFF")  # White text
                cell.fill = cell.fill.copy(start_color="1E1E1E")  # Dark background

        writer.save()
        self.parent.log_message(f"Invoice saved as {excel_filename}")
        self.parent.manage_invoices_tab.load_invoices()
        self.send_email_invoice(client, excel_filename)

    def get_selected_template(self):
        """Retrieves the selected template's attributes."""
        if self.selected_template and self.selected_template in self.parent.templates:
            return self.parent.templates[self.selected_template]
        return {}

    def send_email_invoice(self, client, invoice_path):
        """Send the invoice via email."""
        # Load email configuration
        email_config = self.parent.email_config
        if not email_config:
            QMessageBox.warning(self, "Email Configuration Missing", "Please configure email settings in the 'Email Settings' tab.")
            return

        sender_email = email_config.get("sender_email")
        sender_password = email_config.get("sender_password")
        smtp_server = email_config.get("smtp_server")
        smtp_port = email_config.get("smtp_port")
        if not all([sender_email, sender_password, smtp_server, smtp_port]):
            QMessageBox.warning(self, "Incomplete Email Configuration", "Please complete all email settings.")
            return

        recipient_email = self.parent.clients[client]['email']
        subject = f"Invoice from {self.parent.company_details.get('company_name', 'Your Company')}"
        body = f"Dear {client},\n\nPlease find attached your invoice.\n\nThank you for your business."

        # Create the email message
        msg = MIMEText(body)
        msg['Subject'] = subject
        msg['From'] = sender_email
        msg['To'] = recipient_email

        # Attach the invoice file
        with open(invoice_path, 'rb') as f:
            part = MIMEApplication(f.read(), Name=os.path.basename(invoice_path))
        part['Content-Disposition'] = f'attachment; filename="{os.path.basename(invoice_path)}"'
        msg.attach(part)

        try:
            with smtplib.SMTP(smtp_server, smtp_port) as server:
                server.starttls()
                server.login(sender_email, sender_password)
                server.send_message(msg)
            self.parent.log_message(f"Invoice sent to {client} at {recipient_email}.")
            QMessageBox.information(self, "Email Sent", f"Invoice has been sent to {recipient_email}.")
        except Exception as e:
            QMessageBox.warning(self, "Email Error", f"Failed to send email: {e}")
            self.parent.log_message(f"Failed to send invoice to {client}: {e}")

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, resend, and delete invoices
        btn_layout = QHBoxLayout()
        self.view_invoice_button = QPushButton("View Invoice")
        self.view_invoice_button.clicked.connect(self.view_invoice)
        self.resend_invoice_button = QPushButton("Resend Invoice")
        self.resend_invoice_button.clicked.connect(self.resend_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.resend_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 resend_invoice(self):
        invoice_path = self.get_selected_invoice_path()
        if not invoice_path:
            return
        # Extract client name from filename
        try:
            client_name = invoice_path.split('_invoice_')[0].replace('_', ' ')
            if client_name not in self.parent.clients:
                raise ValueError("Client not found.")
            self.parent.invoice_tab.send_email_invoice(client_name, invoice_path)
        except Exception as e:
            QMessageBox.warning(self, "Resend Error", f"Failed to resend invoice: {e}")
            self.parent.log_message(f"Failed to resend invoice '{invoice_path}': {e}")

    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:
                os.remove(invoice_path)
                self.parent.log_message(f"Invoice '{os.path.basename(invoice_path)}' deleted.")
                self.load_invoices()
            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}")

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 = QtWidgets.QTableWidget()
        self.financial_table.setColumnCount(4)
        self.financial_table.setHorizontalHeaderLabels(["Invoice Number", "Date", "Total (ZAR)", "Status"])
        self.financial_table.horizontalHeader().setStretchLastSection(True)
        layout.addWidget(self.financial_table)

        # Totals Display
        totals_layout = QHBoxLayout()
        self.total_invoiced_label = QLabel("Total Invoiced: R0.00")
        self.total_paid_label = QLabel("Total Paid: R0.00")  # Placeholder, can be implemented if payment tracking exists
        self.balance_label = QLabel("Balance: R0.00")
        totals_layout.addWidget(self.total_invoiced_label)
        totals_layout.addWidget(self.total_paid_label)
        totals_layout.addWidget(self.balance_label)
        layout.addLayout(totals_layout)

        # Load financial statements when client is selected
        self.client_combo.currentIndexChanged.connect(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
        total_paid = 0.0  # Implement payment tracking if needed
        balance = 0.0

        # Iterate through invoices and populate table
        for invoice_file in os.listdir(INVOICES_DIR):
            if not invoice_file.startswith(client_name.replace(' ', '_')):
                continue
            invoice_path = os.path.join(INVOICES_DIR, invoice_file)
            # Determine if invoice is paid or not
            # Placeholder: Assuming all invoices are unpaid
            status = "Unpaid"  # Implement actual payment status if available

            # Extract invoice number and date from filename or file content
            # For simplicity, extract from filename
            try:
                parts = invoice_file.split('_invoice_')
                invoice_number = parts[1].split('.')[0]
            except IndexError:
                invoice_number = "N/A"

            # Read invoice date and total from PDF or Excel
            # For simplicity, set to current date and random total
            # Implement proper extraction if needed
            invoice_date = "2023-10-01"  # Placeholder
            total = 0.0

            # Read from PDF if available
            if invoice_file.lower().endswith('.pdf'):
                # Implement PDF reading if necessary
                # Placeholder value
                total = 100.00
            elif invoice_file.lower().endswith('.xlsx'):
                try:
                    df = pd.read_excel(invoice_path, sheet_name='Invoice')
                    total = df['Total (ZAR)'].sum()
                except:
                    total = 0.0

            total_invoiced += total
            balance += total  # Assuming no payments

            # 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(invoice_number))
            self.financial_table.setItem(row_position, 1, QtWidgets.QTableWidgetItem(invoice_date))
            self.financial_table.setItem(row_position, 2, QtWidgets.QTableWidgetItem(f"R{total:.2f}"))
            self.financial_table.setItem(row_position, 3, QtWidgets.QTableWidgetItem(status))

        self.total_invoiced_label.setText(f"Total Invoiced: R{total_invoiced:.2f}")
        self.total_paid_label.setText(f"Total Paid: R{total_paid:.2f}")
        self.balance_label.setText(f"Balance: R{balance:.2f}")

class EmailConfigTab(QWidget):
    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        self.init_ui()

    def init_ui(self):
        layout = QVBoxLayout()

        # Email configuration form
        form_group = QtWidgets.QGroupBox("Email Configuration")
        form_layout = QVBoxLayout()
        self.sender_email_input = QLineEdit(self)
        self.sender_email_input.setPlaceholderText("Sender Email")
        self.sender_password_input = QLineEdit(self)
        self.sender_password_input.setPlaceholderText("Sender Password")
        self.sender_password_input.setEchoMode(QLineEdit.EchoMode.Password)
        self.smtp_server_input = QLineEdit(self)
        self.smtp_server_input.setPlaceholderText("SMTP Server (e.g., smtp.office365.com)")
        self.smtp_port_input = QLineEdit(self)
        self.smtp_port_input.setPlaceholderText("SMTP Port (e.g., 587)")

        form_layout.addWidget(QLabel("Sender Email:"))
        form_layout.addWidget(self.sender_email_input)
        form_layout.addWidget(QLabel("Sender Password:"))
        form_layout.addWidget(self.sender_password_input)
        form_layout.addWidget(QLabel("SMTP Server:"))
        form_layout.addWidget(self.smtp_server_input)
        form_layout.addWidget(QLabel("SMTP Port:"))
        form_layout.addWidget(self.smtp_port_input)

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

        # Save button
        self.save_email_config_button = QPushButton("Save Email Settings")
        self.save_email_config_button.clicked.connect(self.save_email_config)
        layout.addWidget(self.save_email_config_button)

        self.setLayout(layout)
        self.load_existing_config()

    def load_existing_config(self):
        config = self.parent.email_config
        if config:
            self.sender_email_input.setText(config.get("sender_email", ""))
            self.sender_password_input.setText(config.get("sender_password", ""))
            self.smtp_server_input.setText(config.get("smtp_server", ""))
            self.smtp_port_input.setText(str(config.get("smtp_port", "")))

    def save_email_config(self):
        sender_email = self.sender_email_input.text().strip()
        sender_password = self.sender_password_input.text().strip()
        smtp_server = self.smtp_server_input.text().strip()
        smtp_port = self.smtp_port_input.text().strip()

        if not sender_email or not sender_password or not smtp_server or not smtp_port:
            QMessageBox.warning(self, "Input Error", "Please fill in all fields.")
            return

        try:
            smtp_port = int(smtp_port)
        except ValueError:
            QMessageBox.warning(self, "Input Error", "SMTP Port must be a number.")
            return

        self.parent.email_config = {
            "sender_email": sender_email,
            "sender_password": sender_password,
            "smtp_server": smtp_server,
            "smtp_port": smtp_port
        }
        save_json(self.parent.email_config, EMAIL_CONFIG_FILE)
        self.parent.log_message("Email settings updated.")
        QMessageBox.information(self, "Success", "Email settings have been saved.")

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")
        self.company_logo_path_input = QLineEdit(self)
        self.company_logo_path_input.setPlaceholderText("Logo Path")
        self.browse_logo_button = QPushButton("Browse")
        self.browse_logo_button.clicked.connect(self.browse_logo)

        logo_layout = QHBoxLayout()
        logo_layout.addWidget(self.company_logo_path_input)
        logo_layout.addWidget(self.browse_logo_button)

        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_layout.addWidget(QLabel("Company Logo:"))
        form_layout.addLayout(logo_layout)

        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 browse_logo(self):
        file_path, _ = QFileDialog.getOpenFileName(self, "Select Logo", "", "Image Files (*.png *.jpg *.bmp)")
        if file_path:
            self.company_logo_path_input.setText(file_path)

    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", ""))
            self.company_logo_path_input.setText(details.get("company_logo_path", ""))

    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()
        company_logo_path = self.company_logo_path_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,
            "company_logo_path": company_logo_path
        }
        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.")

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 = QtWidgets.QTableWidget()
        self.financial_table.setColumnCount(4)
        self.financial_table.setHorizontalHeaderLabels(["Invoice Number", "Date", "Total (ZAR)", "Status"])
        self.financial_table.horizontalHeader().setStretchLastSection(True)
        layout.addWidget(self.financial_table)

        # Totals Display
        totals_layout = QHBoxLayout()
        self.total_invoiced_label = QLabel("Total Invoiced: R0.00")
        self.total_paid_label = QLabel("Total Paid: R0.00")  # Placeholder, can be implemented if payment tracking exists
        self.balance_label = QLabel("Balance: R0.00")
        totals_layout.addWidget(self.total_invoiced_label)
        totals_layout.addWidget(self.total_paid_label)
        totals_layout.addWidget(self.balance_label)
        layout.addLayout(totals_layout)

        # Load financial statements when client is selected
        self.client_combo.currentIndexChanged.connect(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
        total_paid = 0.0  # Implement payment tracking if needed
        balance = 0.0

        # Iterate through invoices and populate table
        for invoice_file in os.listdir(INVOICES_DIR):
            if not invoice_file.startswith(client_name.replace(' ', '_')):
                continue
            invoice_path = os.path.join(INVOICES_DIR, invoice_file)
            # Determine if invoice is paid or not
            # Placeholder: Assuming all invoices are unpaid
            status = "Unpaid"  # Implement actual payment status if available

            # Extract invoice number and date from filename or file content
            # For simplicity, extract from filename
            try:
                parts = invoice_file.split('_invoice_')
                invoice_number = parts[1].split('.')[0]
            except IndexError:
                invoice_number = "N/A"

            # Read invoice date and total from PDF or Excel
            # For simplicity, set to current date and random total
            # Implement proper extraction if needed
            invoice_date = "2023-10-01"  # Placeholder
            total = 0.0

            # Read from PDF if available
            if invoice_file.lower().endswith('.pdf'):
                # Implement PDF reading if necessary
                # Placeholder value
                total = 100.00
            elif invoice_file.lower().endswith('.xlsx'):
                try:
                    df = pd.read_excel(invoice_path, sheet_name='Invoice')
                    total = df['Total (ZAR)'].sum()
                except:
                    total = 0.0

            total_invoiced += total
            balance += total  # Assuming no payments

            # 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(invoice_number))
            self.financial_table.setItem(row_position, 1, QtWidgets.QTableWidgetItem(invoice_date))
            self.financial_table.setItem(row_position, 2, QtWidgets.QTableWidgetItem(f"R{total:.2f}"))
            self.financial_table.setItem(row_position, 3, QtWidgets.QTableWidgetItem(status))

        self.total_invoiced_label.setText(f"Total Invoiced: R{total_invoiced:.2f}")
        self.total_paid_label.setText(f"Total Paid: R{total_paid:.2f}")
        self.balance_label.setText(f"Balance: R{balance:.2f}")

class TemplateManagementTab(QWidget):
    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        self.init_ui()

    def init_ui(self):
        layout = QVBoxLayout()

        # List of templates
        self.templates_list = QListWidget()
        self.load_templates()
        layout.addWidget(QLabel("Existing Templates:"))
        layout.addWidget(self.templates_list)

        # Buttons to create, edit, and delete templates
        btn_layout = QHBoxLayout()
        self.create_template_button = QPushButton("Create New Template")
        self.create_template_button.clicked.connect(self.create_template)
        self.edit_template_button = QPushButton("Edit Selected")
        self.edit_template_button.clicked.connect(self.edit_template)
        self.delete_template_button = QPushButton("Delete Selected")
        self.delete_template_button.clicked.connect(self.delete_template)
        btn_layout.addWidget(self.create_template_button)
        btn_layout.addWidget(self.edit_template_button)
        btn_layout.addWidget(self.delete_template_button)
        layout.addLayout(btn_layout)

        self.setLayout(layout)

    def load_templates(self):
        self.templates_list.clear()
        for template in self.parent.templates.keys():
            item = QListWidgetItem(template)
            self.templates_list.addItem(item)

    def create_template(self):
        """Open CreateTemplate.py to create a new template."""
        try:
            os.system("python CreateTemplate.py")  # Ensure CreateTemplate.py exists and is in the same directory
            self.parent.log_message("Opened CreateTemplate.py")
        except Exception as e:
            QMessageBox.warning(self, "Error", f"Failed to open CreateTemplate.py: {e}")

    def edit_template(self):
        """Open EditTemplate.py to edit the selected template."""
        selected_item = self.templates_list.currentItem()
        if not selected_item:
            QMessageBox.warning(self, "Selection Error", "Please select a template to edit.")
            return
        template_name = selected_item.text()
        try:
            os.system("python EditTemplate.py")  # Ensure EditTemplate.py exists and is in the same directory
            self.parent.log_message(f"Opened EditTemplate.py for template '{template_name}'")
        except Exception as e:
            QMessageBox.warning(self, "Error", f"Failed to open EditTemplate.py: {e}")

    def delete_template(self):
        """Logic to delete the selected template."""
        selected_item = self.templates_list.currentItem()
        if not selected_item:
            QMessageBox.warning(self, "Selection Error", "Please select a template to delete.")
            return
        template_name = selected_item.text()
        reply = QMessageBox.question(
            self, 'Delete Confirmation',
            f"Are you sure you want to delete template '{template_name}'?",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
            QMessageBox.StandardButton.No
        )
        if reply == QMessageBox.StandardButton.Yes:
            del self.parent.templates[template_name]
            save_json(self.parent.templates, TEMPLATES_FILE)
            self.parent.log_message(f"Template '{template_name}' deleted.")
            self.load_templates()

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")
        self.company_logo_path_input = QLineEdit(self)
        self.company_logo_path_input.setPlaceholderText("Logo Path")
        self.browse_logo_button = QPushButton("Browse")
        self.browse_logo_button.clicked.connect(self.browse_logo)

        logo_layout = QHBoxLayout()
        logo_layout.addWidget(self.company_logo_path_input)
        logo_layout.addWidget(self.browse_logo_button)

        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_layout.addWidget(QLabel("Company Logo:"))
        form_layout.addLayout(logo_layout)

        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 browse_logo(self):
        file_path, _ = QFileDialog.getOpenFileName(self, "Select Logo", "", "Image Files (*.png *.jpg *.bmp)")
        if file_path:
            self.company_logo_path_input.setText(file_path)

    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", ""))
            self.company_logo_path_input.setText(details.get("company_logo_path", ""))

    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()
        company_logo_path = self.company_logo_path_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,
            "company_logo_path": company_logo_path
        }
        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)

    # Set application icon (optional, ensure you have an icon file)
    # app.setWindowIcon(QtGui.QIcon('icon.png'))

    window = QuickBooksReplacement()
    window.show()
    sys.exit(app.exec())