# Key Sync Service - Sync Engine
# Logic cache compare & ghi Redis, dùng chung cho mọi tool

import json
from datetime import datetime
try:
    from .redis_client import get_redis_connection
except ImportError:
    from redis_client import get_redis_connection


class SyncEngine:
    """Engine đồng bộ key cho 1 tool (tradingview hoặc copytrade)."""

    def __init__(self, tool_name, db, key_hash, fields, force_sync_interval=10):
        self.tool_name = tool_name
        self.db = db
        self.key_hash = key_hash
        self.fields = fields  # Các trường từ API cần so sánh & cập nhật
        self.force_sync_interval = force_sync_interval
        self.cache = {}
        self.sync_counter = 0

    # ── Cache ──────────────────────────────────────────

    def load_cache_from_redis(self):
        """Tải dữ liệu từ Redis vào cache"""
        try:
            r = get_redis_connection(self.db)
            all_keys = r.hgetall(self.key_hash)
            self.cache = {}
            for key, value in all_keys.items():
                try:
                    self.cache[key] = json.loads(value)
                except json.JSONDecodeError:
                    print(f"  [{self.tool_name}] Lỗi parse JSON cho key {key}")
            print(f"  [{self.tool_name}] Đã tải {len(self.cache)} key từ Redis (db={self.db}, hash={self.key_hash})")
        except Exception as e:
            print(f"  [{self.tool_name}] Lỗi tải cache: {e}")
            self.cache = {}

    # ── Compare ────────────────────────────────────────

    def _compare_with_cache(self, new_data_dict):
        """So sánh dữ liệu mới với cache, trả về changes"""
        changes = {
            'to_update': {},
            'to_delete': set(),
            'unchanged': set(),
        }

        # Key cần xóa
        for key in self.cache:
            if self.cache[key].get('username') == 'admin':
                changes['unchanged'].add(key)
                continue
            if key not in new_data_dict:
                changes['to_delete'].add(key)

        # Key cần cập nhật
        for key, new_value in new_data_dict.items():
            if key not in self.cache:
                changes['to_update'][key] = new_value
            else:
                if self.cache[key].get('username') == 'admin':
                    changes['unchanged'].add(key)
                    continue

                old_value = self.cache[key]
                changed = any(
                    old_value.get(f) != new_value.get(f)
                    for f in self.fields
                )

                if changed:
                    merged = old_value.copy()
                    merged.update({f: new_value.get(f, '') for f in self.fields})
                    changes['to_update'][key] = merged
                else:
                    changes['unchanged'].add(key)

        return changes

    # ── Save ───────────────────────────────────────────

    def save_to_redis(self, data_dict):
        """So sánh, xóa/cập nhật Redis, refresh cache"""
        keys_to_delete = set()
        updated_count = 0

        try:
            # Force sync định kỳ
            self.sync_counter += 1
            if self.sync_counter >= self.force_sync_interval:
                self.sync_counter = 0
                print(f"  [{self.tool_name}] Force sync cache từ Redis...")
                self.load_cache_from_redis()

            changes = self._compare_with_cache(data_dict)

            if not changes['to_update'] and not changes['to_delete']:
                return

            now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            print(f"  [{self.tool_name}] [{now}] Phát hiện thay đổi")

            r = get_redis_connection(self.db)

            # Xóa key hết hạn / không còn
            if changes['to_delete']:
                keys_to_delete = set()
                for key in changes['to_delete']:
                    current_value = r.hget(self.key_hash, key)
                    if current_value:
                        try:
                            current_dict = json.loads(current_value)
                            if current_dict.get('username') != 'admin':
                                keys_to_delete.add(key)
                        except json.JSONDecodeError:
                            keys_to_delete.add(key)
                if keys_to_delete:
                    r.hdel(self.key_hash, *keys_to_delete)
                    print(f"  [{self.tool_name}] Đã xóa {len(keys_to_delete)} key")

            # Cập nhật key mới / thay đổi
            if changes['to_update']:
                skipped_admin = 0
                for k, v in changes['to_update'].items():
                    current_value = r.hget(self.key_hash, k)
                    if current_value:
                        try:
                            current_dict = json.loads(current_value)
                            if current_dict.get('username') == 'admin':
                                skipped_admin += 1
                                continue
                            current_dict.update(v)
                            v = current_dict
                        except json.JSONDecodeError:
                            pass
                    r.hset(self.key_hash, k, json.dumps(v))
                    updated_count += 1

                print(f"  [{self.tool_name}] Đã cập nhật {updated_count} key")
                if skipped_admin > 0:
                    print(f"  [{self.tool_name}] Bỏ qua {skipped_admin} key admin")

            # Refresh cache từ Redis
            all_keys = r.hgetall(self.key_hash)
            self.cache = {}
            for key, value in all_keys.items():
                try:
                    self.cache[key] = json.loads(value)
                except json.JSONDecodeError:
                    continue

            admin_keys = sum(1 for v in self.cache.values() if v.get('username') == 'admin')
            print(f"  [{self.tool_name}] Tổng: {len(self.cache)} key (admin: {admin_keys}, "
                  f"cập nhật: {updated_count}, xóa: {len(keys_to_delete)}, "
                  f"không đổi: {len(changes['unchanged'])})")

        except Exception as e:
            print(f"  [{self.tool_name}] Lỗi khi lưu Redis: {e}")
            raise
