import os
import msvcrt
import time
import threading
from datetime import datetime


# S : Skip current directory
# C : Cancel

BLACKLISTS_DIR = [
    "Windows",
    "Dell",
    "Program Files",
    "Program Files (x86)",
    "ProgramData",
    "All Users",
    "Recovery",
    "Application Data"
]

SKIPPED_DIR = []

ORIGINAL_DIR = os.getcwd()
STATS = {}
MAX_DEPTH_SAVE = 7
MAX_DEPTH_LOG = 3
CURRENT_DEPTH = 0
F_COUNTERS = 0
FE_COUNTERS = 0
MIN_FSIZE = (2**20)*30 # > 30MB
ERRORS_DIR = []
RUNNING = True
SKIP_ACTIVE = False

RED = '\033[31m'
GREEN = '\033[32m'
YELLOW = '\033[33m'
BLUE = '\033[34m'
CYAN = '\033[36m'
RESET = '\033[0m'
BRIGHT_BLACK = '\033[90m'
BRIGHT_RED = '\033[91m'
BRIGHT_GREEN = '\033[92m'
BRIGHT_YELLOW = '\033[93m'
BRIGHT_BLUE = '\033[94m'
BRIGHT_MAGENTA = '\033[95m'
BRIGHT_CYAN = '\033[96m'
BRIGHT_WHITE = '\033[97m'

print(f"""
Minimum File Size : {MIN_FSIZE}b
Max Depth (log) : {MAX_DEPTH_LOG}
Max Depth (save) : {MAX_DEPTH_SAVE}
""")

root_dir = input('ROOT (Default C:\\) : ')
if root_dir.strip() == '':
    root_dir = 'C:\\'

fsize = input(f'Min. File Size (Default: {MIN_FSIZE}) : ')
if fsize.strip() != '':
    MIN_FSIZE = int(fsize)

depth = input(f'Max Depth (Default: {MAX_DEPTH_SAVE}): ')
if not depth.strip() == '':
    MAX_DEPTH_SAVE = int(depth)

os.chdir(root_dir)
total_size = 0

def handleKeyPress():
    global RUNNING, SKIP_ACTIVE
    while not total_size:
        time.sleep(1.0)
        # Handling until analyze finished
        if msvcrt.kbhit():
            k = msvcrt.getch()

            if k == b'c' or k == b'C':
                # Stop Analyze
                RUNNING = False

            elif k == b's' or k == b'S':
                # Skip current dir
                SKIP_ACTIVE = True

# Handle KeyPress
handler = threading.Thread(target=handleKeyPress)
handler.start()

def analyzeFolder(folder_path) -> int:

    if not RUNNING:
        return 0

    global CURRENT_DEPTH, FE_COUNTERS, SKIP_ACTIVE, SKIPPED_DIR

    # DEPTH +1
    CURRENT_DEPTH += 1
    last_m = "       "
    size = 0
    c = os.getcwd()
    if CURRENT_DEPTH <= MAX_DEPTH_LOG:
        os.system('cls')
        print('DEPTH:', CURRENT_DEPTH)
        print('CUR :', c)
        print("DIR :", folder_path, '\n')

    for dir in os.listdir(os.getcwd()):
        if SKIP_ACTIVE:
            # SKIP CURRENT DIR
            SKIPPED_DIR.append(os.getcwd())
            
            # RESET
            SKIP_ACTIVE = False
            print('Skipping : ', os.getcwd())
            return 0

        if os.path.isdir(dir):
            if not dir in BLACKLISTS_DIR:    
                # Recursive call
                back_dir = os.getcwd()
                try:
                    os.chdir(dir)
                except PermissionError:
                    print('PermError1, skipping...', dir, 'current:', os.getcwd())
                    FE_COUNTERS += 1
                    continue
                except OSError:
                    print('OSError, skipping...', dir, 'current:', os.getcwd())
                    FE_COUNTERS += 1
                    continue

                try:
                    size += analyzeFolder(dir)
                except PermissionError:
                    print('PermError2, skipping...', dir, 'current:', os.getcwd())
                    FE_COUNTERS += 1
                
                # DEPTH -1
                os.chdir(back_dir)
                CURRENT_DEPTH -= 1

        elif os.path.isfile(dir):
            global F_COUNTERS
            F_COUNTERS += 1
            # Get Size & last modification time
            try:
                size += os.path.getsize(dir)
                timestamp = os.path.getmtime(dir)
                try:    
                    last_m = datetime.fromtimestamp(timestamp).strftime("%Y/%m")
                except OSError:
                    if timestamp < 0:
                        last_m = "0000/00"

            except FileNotFoundError:
                print('File Not Found Error, skipping...', dir)

        else:
            # Check access
            if not os.access(dir, os.R_OK):    
                print('Access refused :', dir)
                FE_COUNTERS += 1
                
            else:
                print('Not a file, neither a dir :', dir)
                ERRORS_DIR.append(dir)

    # UPDATE STATS
    if 1 < CURRENT_DEPTH <= MAX_DEPTH_SAVE:
        if size > MIN_FSIZE:
            STATS[c] = (size, CURRENT_DEPTH, last_m)

    return size

total_size = analyzeFolder(os.getcwd())

# Join handler thread
print('Joining Handler...')
handler.join()

# SORT STATS
# STATS = dict(sorted(STATS.items(), key=lambda item: item[1][0], reverse=True))
STATS = dict(reversed(list(STATS.items())))

# SIZES
mb_s = 2**20
gb_s = 2**30

# RESTORE ORIGNAL DIR
os.chdir(ORIGINAL_DIR)

# CLEAR
os.system('cls')

report = str()
report += str("""
\t\t\t\t\t┌─────────────┐
\t\t\t\t\t│   RESULTS   │
\t\t\t\t\t└─────────────┘
""")

report += str('\n Blacklisted Directories :\n')
for b in BLACKLISTS_DIR:
    report += str(f' - {b}\n')

report += str('\n Skipped Directories :\n')
for b in SKIPPED_DIR:
    report += str(f' - {b}\n')

if len(ERRORS_DIR) > 0:    
    report += str('\n Directories not analyzed :\n')
    for b in ERRORS_DIR:
        report += str(f' - {b}\n')

report += str(f'\n Files: {F_COUNTERS}\n')
report += str(f' Skipped Files : {FE_COUNTERS}\n\n')

for k in list(STATS.keys()):
    
    if STATS[k][0] > gb_s:
        c = RED
    elif STATS[k][0] > 300*mb_s:
        c = YELLOW
    elif STATS[k][0] > 150*mb_s:
        c = CYAN
    else:
        c = GREEN

    if STATS[k][1] == 2:
        path_line = '┌──'
    elif STATS[k][1] > 2:
        path_line = '├──' + '───'* (STATS[k][1])

    # Time Color
    if STATS[k][2] == '       ':
        c2 = ''
    else:    
        year = int(STATS[k][2].split('/')[0])
        if year <= 2017:
            c2 = BRIGHT_WHITE
        elif year <= 2020:
            c2 = BRIGHT_RED
        elif year <= 2022:
            c2 = BRIGHT_YELLOW
        elif year <= 2023:
            c2 = BRIGHT_MAGENTA
        elif year <= 2025:
            c2 = BRIGHT_BLUE

    time_str = f"{c2}{STATS[k][2]}{c}"

    report += str(f"{c} - {STATS[k][0]//mb_s} MB  \t {time_str} {path_line} {k}\n")

# ROOT DIR
report += str(f'{BLUE} - {(total_size//gb_s)/2} GB  \t         └─ {root_dir}\n')

# RESET COLOR
report += str(RESET)

print(report)

# Save report
try:    
    with open('results.txt', 'wb') as f:
        f.write(bytes(report, 'utf-16'))
    print(f'To open report : "type {ORIGINAL_DIR}\\results.txt"')
except PermissionError:
    print('PermError, report not saved')
except:
    print('Cannot save report')

input('\nQUIT\n')