# Copyright 2026 Toyota Research Institute.  All rights reserved.

import os
import cv2
import numpy as np

from glob import glob

from anydata.utils.geometry import invert_extrinsics
from anydata.utils.read import read_numpy, read_yaml, read_image, read_depth, read_json
from anydata.utils.write import write_image, write_npz, write_json
from anydata.converters.utils import run, add_key_to_dict, fill_metadata, parse_dst_seq, frame_name

#######################################################

def convert_extrinsics(extrinsics):
    flip_yz = np.eye(4)
    flip_yz[1, 1] = -1
    flip_yz[2, 2] = -1
    extrinsics = np.matmul(extrinsics, flip_yz)
    return extrinsics

def get_extrinsics(filename, transforms):
    # filename = filename.replace('images', 'poses').replace('.png', '.json')
    # extrinsics = np.array(read_json(filename)['pose'])
    # # extrinsics = convert_extrinsics(extrinsics)
    # # extrinsics = invert_extrinsics(extrinsics)
    # return extrinsics
    for transform in transforms['frames']:        
        if transform['file_path'].endswith(os.path.basename(filename)):
            extrinsics = transform['transform_matrix']
            extrinsics = convert_extrinsics(extrinsics)
            extrinsics = invert_extrinsics(extrinsics)
            return extrinsics
    return None

#######################################################

def get_sequences(args):
    seqs = glob(f'{args.src}/**/transforms.json', recursive=True)
    seqs = [os.path.dirname(seq) for seq in seqs]

    return seqs


def parse_sequence(seq, args):
    return parse_dst_seq(seq, args)

#######################################################

def process_sequence(i, seq, dst, args):

    ### Initialize lists and dicts
    cameras = ['0']
    num_frames = {cam: dict() for cam in cameras}
    resolution = {cam: dict() for cam in cameras}
    labels, lowdim = [], {}

    ### Get filenames
    filename_rgbs = sorted(glob(f'{seq}/images/*.jpg'))
    filename_poses = sorted(glob(f'{seq}/poses/*.json'))

    ### Read transforms for the sequence
    transforms = read_json(f'{seq}/transforms.json')

    ### Get intrinsics
    focal, cx, cy = transforms["fl_x"], transforms["cx"], transforms["cy"]
    intrinsics = np.array([[focal, 0, cx], [0, focal, cy], [0, 0, 1]])

    ############ LOOP OVER CAMERAS
    for cam in cameras:

        ######## RGB FILENAMES
        for i, filename_rgb in enumerate(filename_rgbs):
            frame = frame_name(filename_rgb)

            ######## RGB
            if 'rgb' not in labels: labels.append('rgb')
            rgb = np.array(read_image(filename_rgb))
            filename_rgb_out = f'{dst}/rgb/{cam}/{frame}.jpg'
            write_image(filename_rgb_out, rgb)

            ######## LOWDIM RGB             
            filename_lowdim = add_key_to_dict(lowdim, f'{dst}/lowdim/{cam}/{frame}.npz')
            lowdim[filename_lowdim]['camera'] = cam
            lowdim[filename_lowdim]['timestep'] = int(frame)

            ### Get extrinsics
            extrinsics = get_extrinsics(filename_rgb, transforms)

            ######## INTRINSICS + EXTRINSICS
            if 'intrinsics' not in labels: labels.append('intrinsics')
            if 'extrinsics' not in labels: labels.append('extrinsics')
            filename_lowdim = add_key_to_dict(lowdim, f'{dst}/lowdim/{cam}/{frame}.npz')
            lowdim[filename_lowdim]['extrinsics'] = extrinsics
            lowdim[filename_lowdim]['intrinsics'] = intrinsics

        if len(filename_rgbs) > 0:
            resolution[cam]['rgb'] = rgb.shape[:2]
            num_frames[cam]['rgb'] = len(filename_rgbs)

    ######## WRITE LOWDIM
    for key, val in lowdim.items():
        write_npz(key, val)

############ METADATA 
    filename = f'{dst}/metadata.json'
    seq_metadata = fill_metadata(
        args=args,
        info=dict(
            name='Front3D',
            tags=['real','static','indoor'],
            raw_id=seq.replace(f'{args.src}/', ''),
        ),
        labels=labels,
        cameras=cameras,
        resolution=resolution,
        num_frames=num_frames,
        framerate=10,
        rgb=dict(extension='jpg'),
        intrinsics=dict(model='pinhole'),
        extrinsics=dict(transform='cam2world',metric=True),
        depth=dict(extension='npz',metric=True,sparse=True),
        semantic=None,
        action=None,
        language=None,
        specific=None,
    )
    write_json(filename, seq_metadata)

    return dst

#######################################################

if __name__ == '__main__':
    converter = os.path.basename(__file__)
    run(converter, get_sequences, parse_sequence, process_sequence)

#######################################################





# import json
# import numpy as np
# from glob import glob

# from datasets.dataloaders.BaseDataset import BaseDataset
# from datasets.dataloaders.utils.FolderTree import FolderTree, merge_trees
# from datasets.dataloaders.utils.misc import update_dict, invert_pose
# from datasets.utils.read import read_image, read_depth
# from vidar.utils.data import shuffle_dict
# import os
# import h5py

# class HM3DDataset(BaseDataset):
#     def __init__(self, mask_depth=False, **kwargs):
#         super().__init__(**kwargs, base_tag='folder')

#         self.rgb_folder = 'images'
#         self.rgb_extension = '.png'

#         rgb_trees = []
#         print("self.path", self.path)
#         folders = sorted(glob(f'{self.path}/*'))

#         print(folders)
#         for folder in folders:
#             rgb_trees.append(FolderTree(
#                 f'{folder}', 
#                 context=self.context, 
#                 sub_folders=self.rgb_folder,
#                 suffix=self.rgb_extension,
#             ))
#         self.rgb_tree = merge_trees(rgb_trees)

#         print(self.rgb_tree)

#     def __len__(self):
#         """Dataset length"""
#         return len(self.rgb_tree)

#     @staticmethod
#     def get_rgb(filename):
#         return read_image(filename)

#     def convert_pose(self,C2W):
#         flip_yz = np.eye(4)
#         flip_yz[1, 1] = -1
#         flip_yz[2, 2] = -1
#         C2W = np.matmul(C2W, flip_yz)
#         return C2W

#     def get_pose_and_K(self, filename):

#         parent_folder = os.path.dirname(os.path.dirname(os.path.dirname(filename)))
#         pose_filename = os.path.join(parent_folder, 'train', 'transforms.json')
#         poses = json.load(open(pose_filename))

#         splits = filename.split('/')
#         image_name = splits[-2] + '/' + splits[-1]


#         transform_entry = next(frame for frame in poses['frames'] if frame['file_path'] == image_name)

#         # Extract the transform_matrix
#         C2W = transform_entry['transform_matrix']

#         C2W = self.convert_pose(C2W)
#         #convert_pose to opencv

#         pose = invert_pose(C2W)

#         focal = poses["fl_x"]
#         cx = poses["cx"]
#         cy = poses["cy"]

#         intrinsics = np.array([[focal, 0, cx], [0, focal, cy], [0, 0, 1]])

#         return pose, intrinsics
    

#     def add_target(self, sample, filename, time_cam, **kwargs):
#         update_dict(sample, 'filename', time_cam, filename)

#         pose, intrinsics = self.get_pose_and_K(filename)
#         if self.with_rgb:
#             update_dict(sample, 'rgb', time_cam, 
#                         self.get_rgb(filename))
#         if self.with_intrinsics:
#             update_dict(sample, 'intrinsics', time_cam, 
#                         intrinsics)
#         if self.with_pose:
#             update_dict(sample, 'pose', time_cam, 
#                         pose)
#         self.add_dummy_data(sample, time_cam)
#         return sample

#     def add_context(self, sample, filename_context, **kwargs):
#         for time_cam, filename in filename_context.items():
#             pose, intrinsics = self.get_pose_and_K(filename)
#             update_dict(sample, 'filename',  time_cam, filename)
#             if self.with_rgb_context:
#                 update_dict(sample, 'rgb', time_cam,
#                             self.get_rgb(filename))
#             if self.with_intrinsics_context:
#                 update_dict(sample, 'intrinsics', time_cam, 
#                             intrinsics)
#             if self.with_pose_context:
#                 update_dict(sample, 'pose', time_cam, 
#                             pose)
#             self.add_dummy_data_context(sample, time_cam)
#         return sample