from __future__ import annotations
_A=None
import hashlib,sys
from dataclasses import dataclass
from datetime import datetime,timezone
from pathlib import Path
from typing import Optional
@dataclass
class SourceAudit:fingerprint:str;py_bytes:int;file_count:int;source_mtime:Optional[str]=_A;source_owner:Optional[str]=_A
def _skip_dir(path):return any(A in{'.venv','venv','__pycache__','.git'}for A in path.parts)
def _tracked_files(root):
	A=[]
	for B in sorted(root.rglob('*.py')):
		if _skip_dir(B):continue
		A.append(B)
	C=root/'requirements.txt'
	if C.is_file():A.append(C)
	return A
def file_owner(path):
	try:
		if sys.platform=='win32':
			try:import win32security as A
			except ImportError:return
			D=A.GetFileSecurity(str(path),A.OWNER_SECURITY_INFORMATION);E=D.GetSecurityDescriptorOwner();B,C,F=A.LookupAccountSid(_A,E)
			if C:return f"{C}\\{B}"
			return str(B)
		import pwd;return pwd.getpwuid(path.stat().st_uid).pw_name
	except Exception:return
def python_fingerprint(project_dir):A=audit_sources(project_dir);return A.fingerprint,A.py_bytes,A.file_count
def audit_sources(project_dir):
	E=Path(project_dir)
	if not E.is_dir():return SourceAudit('',0,0)
	A=[];I=0;F=_A;B=-1.
	for C in _tracked_files(E):
		try:J=C.read_bytes();K=C.stat()
		except OSError:continue
		G=C.relative_to(E).as_posix();H=hashlib.sha256(J).hexdigest();D=len(J);I+=D;A.append((G,D,H))
		if K.st_mtime>=B:B=K.st_mtime;F=C
	if not A:return SourceAudit('',0,0)
	L=hashlib.sha256()
	for(G,D,H)in A:L.update(f"{G}:{D}:{H}\n".encode())
	M=_A;N=_A
	if F is not _A and B>=0:M=datetime.fromtimestamp(B,tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC');N=file_owner(F)
	return SourceAudit(fingerprint=L.hexdigest(),py_bytes=I,file_count=len(A),source_mtime=M,source_owner=N)
