import unittest
from dataclasses import replace
from app.contracts.frames import DetectionObservation
from app.pose_nms import pose_nms_indices
from test_pose_path import frame,result


class NmsTest(unittest.TestCase):
    def obs(self,box,score=.7,cls=0):
        return DetectionObservation(frame(),'RFDETRKeypointPreview',cls,score,box)

    def test_overlap_and_score_not_global_threshold(self):
        a=self.obs((0,0,.4,.4),.8)
        b=replace(a,score=.7)
        c=self.obs((.6,.6,1,1),.05)
        self.assertEqual(pose_nms_indices((a,b,c)),(0,2))
        self.assertEqual(pose_nms_indices((b,a,c)),(1,2))

    def test_ties_class_and_frame(self):
        a=self.obs((0,0,1,1))
        self.assertEqual(pose_nms_indices((a,a,replace(a,class_id=1))),(0,2))
        self.assertEqual(pose_nms_indices(()),())
        with self.assertRaises(ValueError):pose_nms_indices((a,replace(a,frame=frame(1))))
        with self.assertRaises(ValueError):pose_nms_indices((a,replace(a,model_key='RFDETRMedium')))

    def test_iou_strict_boundary(self):
        a=self.obs((0,0,1,1),.9)
        self.assertEqual(pose_nms_indices((a,self.obs((0,0,.85,1)))),(0,1))
        self.assertEqual(pose_nms_indices((a,self.obs((0,0,.85001,1)))),(0,))

    def test_shared_schema_and_raw_retention(self):
        r=result()
        r=replace(r,commands=(r.commands[0],replace(r.commands[0],visible=False)),nms_kept=(True,False))
        self.assertEqual(len(r.snapshot()['objects']),1)
        raw=r.snapshot(visible_only=False)
        self.assertEqual(raw['nms']['suppressed'],1)
        self.assertTrue(raw['objects'][1]['nmsSuppressed'])
        self.assertEqual(len(raw['keypointSchema']['names']),17)
        self.assertEqual(raw['keypointSchema']['names'][11],'left_hip')
        self.assertEqual(raw['objects'][0]['keypoints'],raw['objects'][1]['keypoints'])
