from __future__ import annotations
import logging,sqlite3,threading
from pathlib import Path
from admin import config
from admin.models import db
from admin.services.fingerprint import audit_sources
logger=logging.getLogger('ivistaar.watcher')
_started=False
_stop=threading.Event()
ACTOR='auto-deploy'
def start_watcher(app):
	global _started
	if not config.AUTO_DEPLOY_ENABLED:logger.info('Auto-deploy watcher disabled');return
	if _started:return
	_started=True;_stop.clear()
	def A():
		logger.info('Auto-deploy watcher started (interval=%ss)',config.AUTO_DEPLOY_INTERVAL_SEC)
		while not _stop.is_set():
			try:
				with app.app_context():_poll_once()
			except Exception:logger.exception('Watcher poll failed')
			_stop.wait(config.AUTO_DEPLOY_INTERVAL_SEC)
		logger.info('Auto-deploy watcher stopped')
	B=threading.Thread(target=A,name='ivistaar-auto-deploy',daemon=True);B.start()
def stop_watcher():_stop.set()
def _poll_once():
	F='auto_redeploy';from admin.services import deploy as C
	try:G=db.list_deployments()
	except sqlite3.OperationalError:logger.warning('Database not ready; skipping watcher poll');return
	for A in G:
		if not A.auto_deploy:continue
		if A.status=='deploying':continue
		if not A.source_path:continue
		D=Path(A.source_path)
		if not D.is_dir():continue
		B=audit_sources(D)
		if not B.fingerprint:continue
		if A.last_fingerprint and B.fingerprint==A.last_fingerprint:continue
		if not A.last_fingerprint:db.update_fingerprint(A.slug,B.fingerprint,B.py_bytes);continue
		logger.info('Change detected for %s (%s -> %s bytes); auto-redeploying',A.slug,A.last_py_bytes,B.py_bytes);db.add_event(slug=A.slug,event_type='detect',status='info',message=f"Source change detected ({A.last_py_bytes} → {B.py_bytes} tracked bytes); auto-redeploy queued",py_bytes=B.py_bytes,fingerprint=B.fingerprint,actor=ACTOR,source_mtime=B.source_mtime,source_owner=B.source_owner)
		try:C.redeploy(A.slug,event_type=F,actor=ACTOR)
		except C.DeployError as E:logger.warning('Auto-redeploy skipped/failed for %s: %s',A.slug,E);db.add_event(slug=A.slug,event_type=F,status='failed',message=str(E),actor=ACTOR,source_mtime=B.source_mtime,source_owner=B.source_owner)
