from datetime import datetime, timezone
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import func, or_, select, update
from sqlalchemy.orm import Session
from app.api.workspace import get_verified_current_user
from app.db.session import get_db
from app.models.membership import MembershipBranch
from app.models.notification import Notification
from app.models.user import User
from app.services.workspace import get_membership_for_business

router=APIRouter(tags=['Notifications'])
VALID={'LOW_STOCK','SALE_ALERT','DEBT_REMINDER','END_OF_DAY','OFFLINE_QUEUE','GENERAL'}
def visible(db,user,business_id,branch_id=None):
 m=get_membership_for_business(db,user,business_id)
 if not m: raise HTTPException(404,'Business workspace not found.')
 branches=None if m.all_branches else list(db.scalars(select(MembershipBranch.branch_id).where(MembershipBranch.membership_id==m.id)))
 if branch_id and branches is not None and branch_id not in branches: raise HTTPException(403,'You do not have access to this branch.')
 q=select(Notification).where(Notification.business_id==business_id,or_(Notification.user_id==None,Notification.user_id==user.id))
 if branch_id:q=q.where(Notification.branch_id==branch_id)
 elif branches is not None:q=q.where(or_(Notification.branch_id==None,Notification.branch_id.in_(branches)))
 return q
@router.get('/api/businesses/{business_id}/notifications')
def listing(business_id:UUID,category:str|None=None,is_read:bool|None=None,branch_id:UUID|None=None,offset:int=Query(0,ge=0),limit:int=Query(30,ge=1,le=100),user:User=Depends(get_verified_current_user),db:Session=Depends(get_db)):
 q=visible(db,user,business_id,branch_id)
 if category:
  if category not in VALID:raise HTTPException(422,'Invalid notification category.')
  q=q.where(Notification.category==category)
 if is_read is not None:q=q.where(Notification.is_read==is_read)
 return list(db.scalars(q.order_by(Notification.created_at.desc()).offset(offset).limit(limit)))
@router.get('/api/businesses/{business_id}/notifications/unread-count')
def unread(business_id:UUID,user:User=Depends(get_verified_current_user),db:Session=Depends(get_db)):
 return {'count':db.scalar(visible(db,user,business_id).with_only_columns(func.count(Notification.id)).where(Notification.is_read.is_(False))) or 0}
@router.get('/api/businesses/{business_id}/notifications/{notification_id}')
def detail(business_id:UUID,notification_id:UUID,user:User=Depends(get_verified_current_user),db:Session=Depends(get_db)):
 x=db.scalar(visible(db,user,business_id).where(Notification.id==notification_id))
 if not x:raise HTTPException(404,'Notification not found.')
 return x
@router.patch('/api/businesses/{business_id}/notifications/{notification_id}/read')
def mark_read(business_id:UUID,notification_id:UUID,user:User=Depends(get_verified_current_user),db:Session=Depends(get_db)):
 x=db.scalar(visible(db,user,business_id).where(Notification.id==notification_id))
 if not x:raise HTTPException(404,'Notification not found.')
 if not x.is_read:x.is_read=True;x.read_at=datetime.now(timezone.utc);db.commit();db.refresh(x)
 return x
@router.patch('/api/businesses/{business_id}/notifications/read-all')
def read_all(business_id:UUID,user:User=Depends(get_verified_current_user),db:Session=Depends(get_db)):
 ids=visible(db,user,business_id).where(Notification.is_read.is_(False)).with_only_columns(Notification.id)
 result=db.execute(update(Notification).where(Notification.id.in_(ids)).values(is_read=True,read_at=datetime.now(timezone.utc)))
 db.commit();return {'updated':result.rowcount}
