"""
JSON Database Manager
"""
import json
import os
from typing import Any, Dict, List, Optional
from datetime import datetime


class JSONDatabase:
    """Manage JSON-based database operations"""
    
    def __init__(self, db_file: str):
        self.db_file = db_file
        self.ensure_file_exists()
    
    def ensure_file_exists(self):
        """Create file if it doesn't exist"""
        os.makedirs(os.path.dirname(self.db_file), exist_ok=True)
        if not os.path.exists(self.db_file):
            self.save({})
    
    def load(self) -> Dict[str, Any]:
        """Load data from JSON file"""
        try:
            with open(self.db_file, 'r', encoding='utf-8') as f:
                return json.load(f)
        except (json.JSONDecodeError, FileNotFoundError):
            return {}
    
    def save(self, data: Dict[str, Any]):
        """Save data to JSON file"""
        with open(self.db_file, 'w', encoding='utf-8') as f:
            json.dump(data, f, indent=2, ensure_ascii=False)
    
    def get(self, key: str, default=None) -> Any:
        """Get value by key"""
        data = self.load()
        return data.get(key, default)
    
    def set(self, key: str, value: Any):
        """Set value by key"""
        data = self.load()
        data[key] = value
        self.save(data)
    
    def update(self, key: str, updates: Dict[str, Any]):
        """Update nested dictionary"""
        data = self.load()
        if key not in data:
            data[key] = {}
        if isinstance(data[key], dict):
            data[key].update(updates)
            self.save(data)
    
    def delete(self, key: str):
        """Delete key from database"""
        data = self.load()
        if key in data:
            del data[key]
            self.save(data)
    
    def append(self, key: str, item: Any):
        """Append item to list"""
        data = self.load()
        if key not in data:
            data[key] = []
        if isinstance(data[key], list):
            data[key].append(item)
            self.save(data)


class UserManager:
    """Manage user data"""
    
    def __init__(self, db_file: str):
        self.db = JSONDatabase(db_file)
    
    def user_exists(self, user_id: int) -> bool:
        """Check if user exists"""
        users = self.db.load()
        return str(user_id) in users
    
    def create_user(self, user_id: int, username: str, first_name: str):
        """Create new user"""
        users = self.db.load()
        users[str(user_id)] = {
            'id': user_id,
            'username': username,
            'first_name': first_name,
            'balance_coin': 0,
            'balance_toman': 0,
            'active_configs': [],
            'configs_purchased': 0,
            'is_blocked': False,
            'referral_code': None,
            'referrals_count': 0,
            'bonus_points': 0.0,
            'referral_points_spent': 0.0,
            'created_at': datetime.now().isoformat(),
            'last_activity': datetime.now().isoformat()
        }
        self.db.save(users)
    
    def get_user(self, user_id: int) -> Optional[Dict]:
        """Get user data"""
        users = self.db.load()
        return users.get(str(user_id))
    
    def update_user(self, user_id: int, updates: Dict[str, Any]):
        """Update user data"""
        users = self.db.load()
        if str(user_id) in users:
            users[str(user_id)].update(updates)
            users[str(user_id)]['last_activity'] = datetime.now().isoformat()
            self.db.save(users)
    
    def add_coin(self, user_id: int, amount: int):
        """Add coins to user"""
        user = self.get_user(user_id)
        if user:
            user['balance_coin'] += amount
            self.update_user(user_id, {'balance_coin': user['balance_coin']})

    def add_bonus_points(self, user_id: int, points: float):
        """Add manual bonus points to user."""
        user = self.get_user(user_id)
        if user:
            current = float(user.get('bonus_points', 0.0))
            self.update_user(user_id, {'bonus_points': round(current + float(points), 2)})

    def add_bonus_points_all(self, points: float) -> int:
        """Add manual bonus points to all users and return affected count."""
        users = self.db.load()
        count = 0
        for uid, user in users.items():
            current = float(user.get('bonus_points', 0.0))
            user['bonus_points'] = round(current + float(points), 2)
            user['last_activity'] = datetime.now().isoformat()
            count += 1
        self.db.save(users)
        return count
    
    def deduct_coin(self, user_id: int, amount: int) -> bool:
        """Deduct coins from user"""
        user = self.get_user(user_id)
        if user and user['balance_coin'] >= amount:
            user['balance_coin'] -= amount
            self.update_user(user_id, {'balance_coin': user['balance_coin']})
            return True
        return False
    
    def get_all_users(self) -> List[Dict]:
        """Get all users"""
        users = self.db.load()
        return list(users.values())
    
    def get_active_users_count(self) -> int:
        """Get count of active (non-blocked) users"""
        users = self.get_all_users()
        return len([u for u in users if not u.get('is_blocked', False)])
    
    def block_user(self, user_id: int):
        """Block user"""
        self.update_user(user_id, {'is_blocked': True})
    
    def unblock_user(self, user_id: int):
        """Unblock user"""
        self.update_user(user_id, {'is_blocked': False})


class PlansManager:
    """Manage VPN plans"""
    
    def __init__(self, db_file: str):
        self.db = JSONDatabase(db_file)
        self.initialize_default_plans()
    
    def initialize_default_plans(self):
        """Initialize default plans if empty"""
        plans = self.db.load()
        if not plans:
            default_plans = {
                "1": {
                    'id': '1',
                    'name': 'پایه',
                    'volume_gb': 10,
                    'duration_days': 30,
                    'price_toman': 50000,
                    'price_usdt': 2,
                    'description': 'برای کاربران جدید',
                    'active': True
                },
                "2": {
                    'id': '2',
                    'name': 'استاندارد',
                    'volume_gb': 50,
                    'duration_days': 30,
                    'price_toman': 150000,
                    'price_usdt': 6,
                    'description': 'برای کاربران معمولی',
                    'active': True
                },
                "3": {
                    'id': '3',
                    'name': 'پریمیوم',
                    'volume_gb': 200,
                    'duration_days': 30,
                    'price_toman': 400000,
                    'price_usdt': 15,
                    'description': 'برای کاربران حرفه‌ای',
                    'active': True
                }
            }
            self.db.save(default_plans)
    
    def get_all_plans(self) -> List[Dict]:
        """Get all active plans"""
        plans = self.db.load()
        return [p for p in plans.values() if p.get('active', True)]
    
    def get_plan(self, plan_id: str) -> Optional[Dict]:
        """Get specific plan"""
        plans = self.db.load()
        return plans.get(plan_id)
    
    def create_plan(self, plan_data: Dict[str, Any]):
        """Create new plan"""
        plans = self.db.load()
        plan_id = str(max([int(k) for k in plans.keys()], default=0) + 1)
        plan_data['id'] = plan_id
        plan_data['active'] = True
        plans[plan_id] = plan_data
        self.db.save(plans)
    
    def update_plan(self, plan_id: str, updates: Dict[str, Any]):
        """Update plan"""
        plans = self.db.load()
        if plan_id in plans:
            plans[plan_id].update(updates)
            self.db.save(plans)
    
    def delete_plan(self, plan_id: str):
        """Delete/deactivate plan"""
        plans = self.db.load()
        if plan_id in plans:
            plans[plan_id]['active'] = False
            self.db.save(plans)


class ReferralManager:
    """Manage referral system"""
    
    def __init__(self, db_file: str):
        self.db = JSONDatabase(db_file)
    
    def get_referrals(self, user_id: int) -> List[int]:
        """Get list of referral user IDs"""
        data = self.db.load()
        return data.get(str(user_id), {}).get('referrals', [])
    
    def add_referral(self, referrer_id: int, referred_id: int):
        """Add referral relationship"""
        data = self.db.load()
        key = str(referrer_id)
        if key not in data:
            data[key] = {'referrals': []}
        if referred_id not in data[key]['referrals']:
            data[key]['referrals'].append(referred_id)
        self.db.save(data)
    
    def get_referral_stats(self, user_id: int) -> Dict:
        """Get referral statistics"""
        referrals = self.get_referrals(user_id)
        return {
            'total_referrals': len(referrals),
            'referrals': referrals
        }


class TransactionManager:
    """Manage transactions"""
    
    def __init__(self, db_file: str):
        self.db = JSONDatabase(db_file)
    
    def log_transaction(self, user_id: int, transaction_type: str, 
                       amount: float, currency: str, plan_id: str = None, status: str = 'pending'):
        """Log transaction"""
        transactions = self.db.load()
        transaction = {
            'user_id': user_id,
            'type': transaction_type,
            'amount': amount,
            'currency': currency,
            'plan_id': plan_id,
            'status': status,
            'timestamp': datetime.now().isoformat()
        }
        if 'transactions' not in transactions:
            transactions['transactions'] = []
        transactions['transactions'].append(transaction)
        self.db.save(transactions)
    
    def get_user_transactions(self, user_id: int) -> List[Dict]:
        """Get user transactions"""
        transactions = self.db.load()
        return [t for t in transactions.get('transactions', []) 
                if t['user_id'] == user_id]
    
    def get_total_sales(self) -> float:
        """Get total sales"""
        transactions = self.db.load()
        total = 0
        for t in transactions.get('transactions', []):
            if t.get('status') == 'completed':
                total += t.get('amount', 0)
        return total


class OrderManager:
    """Manage user orders for manual admin fulfillment."""

    def __init__(self, db_file: str):
        self.db = JSONDatabase(db_file)
        self._ensure_defaults()

    def _ensure_defaults(self):
        data = self.db.load()
        changed = False
        if 'last_id' not in data:
            data['last_id'] = 0
            changed = True
        if 'orders' not in data:
            data['orders'] = []
            changed = True
        if changed:
            self.db.save(data)

    def _next_id(self) -> str:
        data = self.db.load()
        last_id = int(data.get('last_id', 0)) + 1
        data['last_id'] = last_id
        self.db.save(data)
        return str(last_id)

    def create_order(self, user_id: int, order_type: str, amount: float = 0,
                     currency: str = '', plan_id: str = '', note: str = '') -> dict:
        data = self.db.load()
        order = {
            'id': self._next_id(),
            'user_id': user_id,
            'order_type': order_type,
            'amount': amount,
            'currency': currency,
            'plan_id': plan_id,
            'note': note,
            'status': 'pending',
            'config_link': '',
            'created_at': datetime.now().isoformat(),
            'completed_at': '',
            'completed_by': None,
        }
        data = self.db.load()
        if 'orders' not in data:
            data['orders'] = []
        data['orders'].append(order)
        self.db.save(data)
        return order

    def get_pending_orders(self) -> List[Dict]:
        data = self.db.load()
        return [o for o in data.get('orders', []) if o.get('status') == 'pending']

    def get_order(self, order_id: str) -> Optional[Dict]:
        data = self.db.load()
        for order in data.get('orders', []):
            if str(order.get('id')) == str(order_id):
                return order
        return None

    def complete_order(self, order_id: str, admin_id: int, config_link: str) -> bool:
        data = self.db.load()
        updated = False
        for order in data.get('orders', []):
            if str(order.get('id')) == str(order_id) and order.get('status') == 'pending':
                order['status'] = 'completed'
                order['config_link'] = config_link
                order['completed_by'] = admin_id
                order['completed_at'] = datetime.now().isoformat()
                updated = True
                break
        if updated:
            self.db.save(data)
        return updated

    def user_has_pending(self, user_id: int, order_type: str) -> bool:
        data = self.db.load()
        for order in data.get('orders', []):
            if order.get('user_id') == user_id and order.get('order_type') == order_type and order.get('status') == 'pending':
                return True
        return False


class UISettingsManager:
    """Manage admin-editable UI templates and button payloads."""

    def __init__(self, db_file: str):
        self.db = JSONDatabase(db_file)
        self.ensure_defaults()

    def ensure_defaults(self):
        data = self.db.load()
        changed = False
        if 'welcome_text' not in data:
            data['welcome_text'] = None
            changed = True
        if 'welcome_buttons' not in data:
            data['welcome_buttons'] = None
            changed = True
        if 'force_join' not in data:
            data['force_join'] = {
                'enabled': False,
                'targets': []
            }
            changed = True
        if 'text_templates' not in data:
            data['text_templates'] = {}
            changed = True
        if changed:
            self.db.save(data)

    def get_welcome_text(self):
        data = self.db.load()
        return data.get('welcome_text')

    def set_welcome_text(self, text: str):
        data = self.db.load()
        data['welcome_text'] = text
        self.db.save(data)

    def get_welcome_buttons(self):
        data = self.db.load()
        return data.get('welcome_buttons')

    def set_welcome_buttons(self, buttons_payload):
        data = self.db.load()
        data['welcome_buttons'] = buttons_payload
        self.db.save(data)

    def get_force_join(self):
        data = self.db.load()
        return data.get('force_join', {'enabled': False, 'targets': []})

    def set_force_join(self, enabled: bool, targets: list[str]):
        data = self.db.load()
        data['force_join'] = {
            'enabled': bool(enabled),
            'targets': targets,
        }
        self.db.save(data)

    def get_text_template(self, key: str, default: str = "") -> str:
        data = self.db.load()
        templates = data.get('text_templates', {})
        return templates.get(key, default)

    def set_text_template(self, key: str, value: str):
        data = self.db.load()
        templates = data.get('text_templates', {})
        templates[key] = value
        data['text_templates'] = templates
        self.db.save(data)
