from __future__ import annotations
import hashlib, json, os, shutil, sqlite3, sys
from datetime import datetime, timezone
from pathlib import Path
from sqlalchemy import text
from sqlalchemy.orm import Session
from app.core.config import settings
from app.models.entities import ImplementationProjectV034, NativeBackupRunV034, PlatformDiagnosticRunV034

STEPS=[
 ('company_profile','Dados da empresa'),('branding','Identidade visual'),('first_connection','Primeira conexão'),
 ('catalog','Catálogo de dados'),('governance','Governança'),('pipeline','Primeiro pipeline'),
 ('dashboard','Primeiro dashboard'),('ai','Agente de IA'),('users','Convite de usuários'),('report_schedule','Relatório agendado')]

def default_checklist(): return [{'code':c,'label':l,'status':'pending'} for c,l in STEPS]

def recalc_project(project:ImplementationProjectV034):
    items=project.checklist or default_checklist(); done=sum(1 for i in items if i.get('status')=='completed')
    project.progress_percent=round(done*100/len(items)); project.status='completed' if done==len(items) else 'in_progress'
    project.current_step=next((i['code'] for i in items if i.get('status')!='completed'),'completed')
    if project.status=='completed' and not project.completed_at: project.completed_at=datetime.now(timezone.utc)
    return project

def run_diagnostics(db:Session, tenant_id:str|None, user_id:str):
    checks=[]
    def add(name,ok,detail,critical=False): checks.append({'name':name,'ok':bool(ok),'detail':detail,'critical':critical})
    try: db.execute(text('SELECT 1')); add('database',True,'Conexão com o banco aprovada',True)
    except Exception as e: add('database',False,str(e),True)
    root=Path(getattr(settings,'local_storage_path','storage/data')); root.mkdir(parents=True,exist_ok=True)
    add('storage_write',os.access(root,os.W_OK),str(root),True)
    add('python_version',sys.version_info >= (3,11),sys.version.split()[0],True)
    env=Path('.env'); add('env_permissions',env.exists() and (os.name=='nt' or oct(env.stat().st_mode & 0o777) in {'0o600','0o640'}), 'Arquivo .env protegido')
    add('redis_optional',bool(getattr(settings,'redis_url','')),'Opcional no modo nativo')
    score=round(sum(1 for x in checks if x['ok'])*100/len(checks)); rec=[f"Corrigir: {x['name']} - {x['detail']}" for x in checks if not x['ok']]
    run=PlatformDiagnosticRunV034(tenant_id=tenant_id,scope='tenant' if tenant_id else 'platform',status='success' if all(x['ok'] or not x['critical'] for x in checks) else 'attention',score=score,checks=checks,recommendations=rec,started_by=user_id,finished_at=datetime.now(timezone.utc))
    db.add(run); db.commit(); db.refresh(run); return run

def create_native_backup(db:Session, tenant_id:str|None, user_id:str):
    run=NativeBackupRunV034(tenant_id=tenant_id,started_by=user_id,status='running'); db.add(run); db.commit(); db.refresh(run)
    try:
        out=Path('storage/backups'); out.mkdir(parents=True,exist_ok=True); stamp=datetime.now().strftime('%Y%m%d-%H%M%S')
        target=out/f'metadata-{stamp}-{run.id}.sqlite'
        url=str(settings.database_url)
        if url.startswith('sqlite'):
            source=Path(url.split('///',1)[-1]); shutil.copy2(source,target)
        else:
            target=target.with_suffix('.json'); target.write_text(json.dumps({'created_at':datetime.now(timezone.utc).isoformat(),'database':'external','note':'Use pg_dump/mysqldump for full restore'},ensure_ascii=False,indent=2))
        data=target.read_bytes(); run.file_path=str(target); run.size_bytes=len(data); run.checksum_sha256=hashlib.sha256(data).hexdigest(); run.status='success'; run.finished_at=datetime.now(timezone.utc)
    except Exception as e: run.status='failed'; run.error_message=str(e); run.finished_at=datetime.now(timezone.utc)
    db.commit(); db.refresh(run); return run
