import os
import json
import datetime
import copy
import cv2
from .db_adapter import DatabaseAdapterBase


class JsonAdapterFovEvents(DatabaseAdapterBase):
    """Persist FOV events to JSON files and save images (original frames)."""

    def __init__(self, db_controller=None):
        self.image_dir = None
        self.base_dir = None
        super().__init__(db_controller or self)
        self.preview_width = 320
        self.preview_height = 240

    def get_params(self):
        return {'image_dir': self.image_dir}

    def get_cameras_params(self):
        return {}

    def set_params_impl(self):
        cfg = self.params or {}
        self.image_dir = cfg.get('image_dir', 'EvilEyeData')
        self.base_dir = os.path.join(self.image_dir, 'Events')
        self.event_name = 'FieldOfViewEvent'
        self.table_name = 'fov_events_json'

    def init_impl(self):
        os.makedirs(self.base_dir, exist_ok=True)

    def start(self):
        self.run_flag = True

    def stop(self):
        self.run_flag = False

    def _execute_query(self):
        pass

    def _insert_impl(self, event):
        self._write_event(event, is_update=False)

    def _update_impl(self, event):
        self._write_event(event, is_update=True)

    def _write_event(self, event, is_update: bool):
        date_folder = datetime.date.today().strftime('%Y-%m-%d')
        day_dir = os.path.join(self.base_dir, date_folder)
        metadata_dir = os.path.join(day_dir, 'Metadata')
        os.makedirs(metadata_dir, exist_ok=True)
        file_name = 'fov_events_lost.json' if is_update else 'fov_events_found.json'
        file_path = os.path.join(metadata_dir, file_name)

        records = []
        if os.path.isfile(file_path):
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    records = json.load(f) or []
            except Exception:
                records = []

        ts = (event.time_lost or event.time_obj_detected or event.timestamp)
        preview_rel, frame_rel = self._save_images(day_dir, event, is_update)

        # FOV events do not carry box; keep paths and ids only
        rec = {
            'event_id': event.event_id,
            'ts': ts.isoformat() if hasattr(ts, 'isoformat') else str(ts),
            'source_id': event.source_id,
            'object_id': event.object_id,
            'preview_path': preview_rel,
            'frame_path': frame_rel,
        }
        records.append(rec)
        with open(file_path, 'w', encoding='utf-8') as f:
            json.dump(records, f, ensure_ascii=False, indent=2)

    def _save_images(self, day_dir: str, event, is_update: bool):
        # Новые каталоги: Events/.../Images/FoundFrames/FoundPreviews/LostFrames/LostPreviews
        ts = (event.time_lost if is_update else (event.time_obj_detected or event.timestamp))
        ts_str = ts.strftime('%Y-%m-%d_%H-%M-%S-%f') if is_update else ts.strftime('%Y-%m-%d_%H-%M-%S.%f')
        images_dir = os.path.join(day_dir, 'Images')
        if is_update:
            # Lost event
            previews_dir = os.path.join(images_dir, 'LostPreviews')
            frames_dir = os.path.join(images_dir, 'LostFrames')
        else:
            # Found event (detected)
            previews_dir = os.path.join(images_dir, 'FoundPreviews')
            frames_dir = os.path.join(images_dir, 'FoundFrames')
        os.makedirs(previews_dir, exist_ok=True)
        os.makedirs(frames_dir, exist_ok=True)

        image = event.img_lost if is_update else event.img_detected
        if image is None or not hasattr(image, 'image'):
            return '', ''

        preview = cv2.resize(copy.deepcopy(image.image), (320, 240), cv2.INTER_NEAREST)
        preview_name = f'{ts_str}_src{event.source_id}_preview.jpeg'
        frame_name = f'{ts_str}_src{event.source_id}_frame.jpeg'
        cv2.imwrite(os.path.join(previews_dir, preview_name), preview)
        cv2.imwrite(os.path.join(frames_dir, frame_name), image.image)
        # Return relative to image_dir
        preview_rel = os.path.relpath(os.path.join(previews_dir, preview_name), self.image_dir)
        frame_rel = os.path.relpath(os.path.join(frames_dir, frame_name), self.image_dir)
        return preview_rel, frame_rel


