import datetime
import os
import re
import gzip
import argparse
import time
import zstandard as zstd
from fastwarc.warc import ArchiveIterator
import io
from concurrent.futures import ProcessPoolExecutor

def read_skippable_frame(file):
    magic_number = file.read(4)
    if magic_number != b'\x28\xB5\x2F\xFD':
        return None
    frame_size = int.from_bytes(file.read(4), 'little')
    return file.read(frame_size)

def process_warc(args):
    file_path, output_file_path, pattern = args
    print(f"Processing file: {file_path}")
    counter = 0
    matches_buffer = []

    if file_path.endswith('.warc.gz'):
        warc_stream = gzip.open(file_path, 'rb')
    elif file_path.endswith('.warc.zst'):
        with open(file_path, 'rb') as raw_file:
            dict_data = read_skippable_frame(raw_file)
            dctx = zstd.ZstdDecompressor(dict_data=dict_data)
            remaining_data = raw_file.read()
            warc_stream = io.BytesIO(dctx.decompress(remaining_data))
    else:
        warc_stream = open(file_path, 'rb')

    with warc_stream:
        file_size = os.path.getsize(file_path)
        last_printed_progress = -5  # Initialize to -5 so that it prints at 0% progress

        for record in ArchiveIterator(warc_stream):
            if record.record_type == 4:
                content = record.reader.read().decode(errors='replace')
                matches = pattern.findall(content)
                for match in matches:
                    matches_buffer.append(match)
                    counter += 1

                    if counter % 100 == 0:
                        with open(output_file_path, 'a') as output_file:
                            output_file.write('\n'.join(matches_buffer) + '\n')
                        matches_buffer = []

            # Calculate and print progress every 5%
            progress = (warc_stream.tell() / file_size) * 100
            if progress - last_printed_progress >= 0.1:
                print(f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}:Progress on {file_path}: {progress:.2f}%")
                last_printed_progress = progress

    # Write the remaining matches
    if matches_buffer:
        with open(output_file_path, 'a') as output_file:
            output_file.write('\n'.join(matches_buffer) + '\n')

    print(f"Removing file: {file_path}")
    os.remove(file_path)  # Remove the WARC file after processing

def process_warcs_in_directory(warc_directory, output_file_path, pattern):
    while True:
        with ProcessPoolExecutor(max_workers=12) as executor:
            for file_name in os.listdir(warc_directory):
                if file_name.endswith(('.warc.gz', '.warc.zst')):
                    file_path = os.path.join(warc_directory, file_name)
                    executor.submit(process_warc, (file_path, output_file_path, pattern))

        print("Sleeping 60s")
        time.sleep(60)  # Wait for 60 seconds before checking the directory again

def main(args):
    regex_pattern = r'\S*imgur\S*'
    pattern = re.compile(regex_pattern)

    while True:
        process_warcs_in_directory(args.warc_directory, args.output_file_path, pattern)
        time.sleep(60)  # Wait for 60 seconds before checking the directory again

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Process WARC files and find matches for a regex pattern.')
    parser.add_argument('warc_directory', help='Path to the directory containing WARC files.')
    parser.add_argument('output_file_path', help='Path to the output file.')

    args = parser.parse_args()
    main(args)