from __future__ import annotations
from fastapi import APIRouter, Form, Request
from fastapi.responses import RedirectResponse
from sqlalchemy import select
from app.core.db.common import CommonSessionLocal
from app.core.security.csrf import get_or_create_csrf_token, validate_csrf
from app.core.security.session_auth import get_current_user
from app.core.templating import templates
from app.modules.clients.models import Client
from app.modules.core.rbac.models import Permission, RolePermission, UserRole
from .models import ClientIdentityAuditLog, ClientPortalInvitation
from .service import ensure_identity, get_identity, issue_client_invitation, update_login_email
router=APIRouter(prefix="/client-identity", tags=["client-identity"])

def _has(db,user,code):
    return db.execute(select(Permission.id).join(RolePermission,RolePermission.permission_id==Permission.id).join(UserRole,UserRole.role_id==RolePermission.role_id).where(UserRole.user_id==user.id,Permission.code==code,Permission.is_active.is_(True))).first() is not None

def _load(db,user,client_id):
    c=db.get(Client,client_id)
    if not c or c.tenant_id!=user.tenant_id: return None
    if user.branch_id and c.branch_id!=user.branch_id and not _has(db,user,"clients.view_all_branches"): return None
    return c

@router.get("/clients/{client_id}")
def identity_page(request:Request,client_id:int):
    db=CommonSessionLocal()
    try:
        user=get_current_user(request,db=db)
        if not user:return RedirectResponse('/login',303)
        if not _has(db,user,'clients.view'):return RedirectResponse('/clients?error=Access+denied',303)
        client=_load(db,user,client_id)
        if not client:return RedirectResponse('/clients?error=Client+not+found',303)
        identity=get_identity(db,client.id)
        invites=[]; audits=[]
        if identity:
            invites=list(db.execute(select(ClientPortalInvitation).where(ClientPortalInvitation.identity_id==identity.id).order_by(ClientPortalInvitation.id.desc())).scalars().all())
            audits=list(db.execute(select(ClientIdentityAuditLog).where(ClientIdentityAuditLog.identity_id==identity.id).order_by(ClientIdentityAuditLog.id.desc()).limit(30)).scalars().all())
        return templates.TemplateResponse('client_identity/detail.html',{'request':request,'current_user':user,'csrf_token':get_or_create_csrf_token(request),'client':client,'identity':identity,'invites':invites,'audits':audits,'can_manage':_has(db,user,'clients.edit'),'invite_url':request.session.pop('client_invite_url',None),'flash':request.session.pop('client_identity_flash',None)})
    finally:db.close()

@router.post("/clients/{client_id}/create")
def create_identity(request:Request,client_id:int,email:str=Form(''),csrf_token:str=Form(...)):
    validate_csrf(request,csrf_token);db=CommonSessionLocal()
    try:
        user=get_current_user(request,db=db)
        if not user or not _has(db,user,'clients.edit'):return RedirectResponse('/clients?error=Access+denied',303)
        client=_load(db,user,client_id)
        if not client:return RedirectResponse('/clients?error=Client+not+found',303)
        try: ensure_identity(db,client=client,actor_user_id=user.id,requested_email=email or None);request.session['client_identity_flash']='Client portal identity created.'
        except Exception as exc: request.session['client_identity_flash']=str(exc)
        return RedirectResponse(f'/client-identity/clients/{client_id}',303)
    finally:db.close()

@router.post("/clients/{client_id}/email")
def change_email(request:Request,client_id:int,email:str=Form(...),csrf_token:str=Form(...)):
    validate_csrf(request,csrf_token);db=CommonSessionLocal()
    try:
        user=get_current_user(request,db=db)
        if not user or not _has(db,user,'clients.edit'):return RedirectResponse('/clients?error=Access+denied',303)
        client=_load(db,user,client_id); identity=get_identity(db,client_id) if client else None
        try:
            if not identity: raise ValueError('Create the PAN identity first.')
            update_login_email(db,identity=identity,email=email,actor_user_id=user.id);request.session['client_identity_flash']='Client portal email updated.'
        except Exception as exc: request.session['client_identity_flash']=str(exc)
        return RedirectResponse(f'/client-identity/clients/{client_id}',303)
    finally:db.close()

@router.post("/clients/{client_id}/invite")
def invite(request:Request,client_id:int,send_email:str=Form('1'),csrf_token:str=Form(...)):
    validate_csrf(request,csrf_token);db=CommonSessionLocal()
    try:
        user=get_current_user(request,db=db)
        if not user or not _has(db,user,'clients.edit'):return RedirectResponse('/clients?error=Access+denied',303)
        client=_load(db,user,client_id); identity=get_identity(db,client_id) if client else None
        try:
            if not identity: identity=ensure_identity(db,client=client,actor_user_id=user.id)
            token,row=issue_client_invitation(db,identity=identity,actor_user_id=user.id,send_email=send_email=='1')
            request.session['client_invite_url']=f"{str(request.base_url).rstrip('/')}/invite/accept?token={token}"
            request.session['client_identity_flash']='Invitation issued. Copy the link now; the token is not stored in plain text.'
        except Exception as exc: request.session['client_identity_flash']=str(exc)
        return RedirectResponse(f'/client-identity/clients/{client_id}',303)
    finally:db.close()
