import pdfplumber
import pandas as pd
import re
import sys
from typing import Optional
from tqdm import tqdm

EMPLOYEE_LINE_RE = re.compile(
    r"^(?P<employee_no>\d+)\s+(?P<initial>[A-Z])\s+(?P<last_name>[A-Z]+)(?:\s+(?P<carryin_flag>CARRYIN))?$"
)

HOURS_LINE_RE = re.compile(
    r"^(?P<block_hours>\d{1,2}:\d{2})\s+(?P<carryin_hours>\d{1,2}:\d{2})(?:\s+(?P<codes>.*))?$"
)


def hhmm_to_decimal(value: str) -> float:
    hours, minutes = value.split(":", 1)
    return int(hours) + (int(minutes) / 60)

def parse_bidpac(pdf_path: str, output_path: str):
    rows = []
    pending_employee: Optional[tuple[int, re.Match[str]]] = None

    with pdfplumber.open(pdf_path) as pdf:
        for page_num, page in enumerate(
            tqdm(pdf.pages, total=len(pdf.pages), desc="Parsing pages", unit="page"),
            start=1,
        ):
            text = page.extract_text()
            if not text:
                continue

            lines = [line.strip() for line in text.splitlines() if line.strip()]

            i = 0

            if pending_employee is not None and lines:
                pending_page, pending_match = pending_employee
                hours_match = HOURS_LINE_RE.match(lines[0])

                if hours_match:
                    rows.append({
                        "page": pending_page,
                        "employee_no": pending_match.group("employee_no"),
                        "initial": pending_match.group("initial"),
                        "last_name": pending_match.group("last_name"),
                        "carryin_flag": bool(pending_match.group("carryin_flag")),
                        "block_hours": hhmm_to_decimal(hours_match.group("block_hours")),
                        "carryin_hours": hhmm_to_decimal(hours_match.group("carryin_hours")),
                        "codes": (hours_match.group("codes") or "").strip(),
                    })
                    pending_employee = None
                    i = 1

            while i < len(lines):
                emp_match = EMPLOYEE_LINE_RE.match(lines[i])

                if emp_match and i + 1 < len(lines):
                    hours_match = HOURS_LINE_RE.match(lines[i + 1])

                    if hours_match:
                        rows.append({
                            "page": page_num,
                            "employee_no": emp_match.group("employee_no"),
                            "initial": emp_match.group("initial"),
                            "last_name": emp_match.group("last_name"),
                            "carryin_flag": bool(emp_match.group("carryin_flag")),
                            "block_hours": hhmm_to_decimal(hours_match.group("block_hours")),
                            "carryin_hours": hhmm_to_decimal(hours_match.group("carryin_hours")),
                            "codes": (hours_match.group("codes") or "").strip(),
                        })
                        i += 2
                        continue

                    if i + 1 == len(lines):
                        pending_employee = (page_num, emp_match)
                        i += 1
                        continue

                i += 1

    df = pd.DataFrame(rows)
    df.to_csv(output_path, index=False)
    print(f"\nParsed {len(df)} employee rows to {output_path}")

if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("Usage: python parse_bidpac.py input.pdf output.csv")
        sys.exit(1)

    parse_bidpac(sys.argv[1], sys.argv[2])
