import subprocess
import os
import logging


class ModelConfig:

    def __init__(self):
        home = os.path.expanduser("~/")
        printer_data_config = os.path.join(home, "printer_data", "config")
        self.moonraker_config_path = printer_data_config + "/moonraker.conf"
        self.klipperscreen_config_path = printer_data_config + "/KlipperScreen.conf"
        self.printer_config_path = printer_data_config + "/printer.cfg"

    def get_mac_address(self, interface):
        try:
            result = subprocess.run(
                ["ip", "link", "show", interface], capture_output=True, text=True
            )
            output = result.stdout

            for line in output.split("\n"):
                if "link/ether" in line:
                    mac_address = line.split()[1]
                    return mac_address

        except Exception as e:
            logging.error(f"get mac address error: {e}")
            return None

    def generate_machine_name(self, model):
        mac_address = self.get_mac_address("eth0")
        if mac_address:
            mac_address = mac_address.replace(":", "")
            last_four = mac_address[-4:]
            machine_name = f"{model}-{last_four.upper()}"
            return machine_name
        else:
            return None

    def wirte_printer_config(self, device_name):
        if device_name:
            source_path = f"{os.path.expanduser('~')}/KlipperScreen/printer_config/{device_name}/"
            target_path = f"{os.path.expanduser('~')}/printer_data/config/"
            if not os.path.exists(target_path):
                os.makedirs(target_path)
            source_base_path = os.path.join(source_path, os.path.basename("base.cfg"))
            target_base_path = os.path.join(target_path, os.path.basename("base.cfg"))
            try:
                if os.path.islink(target_base_path) or os.path.exists(target_base_path):
                    os.remove(target_base_path)
                os.symlink(source_base_path, target_base_path)
                logging.info(f"Created config symlink for {device_name}.")
            except FileExistsError:
                logging.error(f"Failed to create config symlink for {device_name}.")
            except PermissionError:
                logging.error(f"No permission to create symlink for {device_name}.")
            except Exception as e:
                logging.error(f"Error creating symlink for{device_name}:{e}")

            source_printer_path = os.path.join(source_path, os.path.basename("printer.cfg"))
            target_printer_path = os.path.join(target_path, os.path.basename("printer.cfg"))
            command = ['cp','-f', source_printer_path, target_printer_path]
            try:
                subprocess.run(command, check=True, text=True, capture_output=True)
                logging.info(f"Configuration file copied successfully. {source_printer_path}' to '{target_printer_path}'")
            except subprocess.CalledProcessError as e:
                logging.error(f"Copy error config file: {e.stderr}")
            except Exception as e:
                logging.error(f"Copy error printer file: {e.stderr}")

    def wirte_hostname(self, device_name):

        try:
            current_hostname = subprocess.check_output(["hostname"], text=True).strip()
            logging.info(f"Current hostname: {current_hostname}")
            subprocess.run(["hostnamectl", "set-hostname", device_name], check=True)
            logging.info(f"Hostname has been changed to: {device_name}")
        except subprocess.CalledProcessError as e:
            logging.error(f"Error while executing command: {e}")
        except Exception as e:
            logging.error(f"An unexpected error occurred: {e}")

    def generate_config(self, model):
        model_name = model
        device_name = self.generate_machine_name(model_name)
        self.wirte_printer_config(model)
        self.wirte_hostname(device_name)
        os.system("systemctl restart klipper.service")
        os.system("systemctl restart moonraker.service")
        os.system("systemctl restart KlipperScreen.service")
