import logging
from django.db import models
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.hashers import make_password, check_password
from shared_models.common.base import BaseModel
from shared_models.common.utils import generate_referral_code
from encrypted_model_fields.fields import EncryptedEmailField, EncryptedCharField
from shared_models.common.mixins import SensitiveFieldsTrackingMixin
import hashlib
from .enums import KycStatus, IbStatus, LeadStatus # Import the new enums

logger = logging.getLogger(__name__)

class Customer(SensitiveFieldsTrackingMixin, BaseModel):
    # Sensitive fields with encryption
    id = models.AutoField(primary_key=True, editable=False)
    email = models.EmailField(_('email address'), unique=True)
    first_name = models.CharField(max_length=150, blank=True)
    last_name = models.CharField(max_length=150, blank=True)
    phone = models.CharField(max_length=20, blank=True)
    mobile = models.CharField(max_length=20, blank=True)
    
    # Define sensitive fields for tracking
    sensitive_fields = []
    requires_approval_fields = []  # Changes to email require approval
    
    # Your existing fields
    country = models.CharField(max_length=20, blank=True)
    nationality = models.CharField(max_length=2, blank=True)
    source = models.CharField(max_length=20, blank=True)

    # IB Relationships
    ib = models.ForeignKey('customers.Customer', on_delete=models.SET_NULL, null=True, blank=True, related_name='referred_customers')
    agreement_id = models.CharField(max_length=100, blank=True)

    # Account Status
    is_funded = models.BooleanField(default=False)
    first_deposit = models.DateTimeField(null=True)
    is_individual = models.BooleanField(default=True)
    is_lead = models.BooleanField(default=False)
    is_client = models.BooleanField(default=False)
    is_ib = models.BooleanField(default=False)
    is_real = models.BooleanField(default=False)
    is_live = models.BooleanField(default=False)
    is_corporate = models.BooleanField(default=False)
    
    # Forms
    submit_individual_form = models.BooleanField(default=False)
    submit_corporate_form = models.BooleanField(default=False)
    submit_ib_form = models.BooleanField(default=False)
    
    # KYC Status - Using Enum
    kyc_status = models.CharField(max_length=20, choices=KycStatus.choices, default=KycStatus.NOT_UPLOADED)
    level_one_kyc_status = models.CharField(max_length=20, choices=KycStatus.choices, default=KycStatus.NOT_UPLOADED)
    level_two_kyc_status = models.CharField(max_length=20, choices=KycStatus.choices, default=KycStatus.NOT_UPLOADED)
    level_three_kyc_status = models.CharField(max_length=20, choices=KycStatus.choices, default=KycStatus.NOT_UPLOADED)
    level_three_kyc_required = models.BooleanField(default=False)
    level_one_approved_date = models.DateTimeField(null=True)
    level_two_approved_date = models.DateTimeField(null=True)
    level_three_approved_date = models.DateTimeField(null=True)

    # IB Status - Using Enum
    ib_status = models.CharField(max_length=20, choices=IbStatus.choices, null=True, blank=True)
    
    # Trading Status
    start_trading = models.BooleanField(default=False)
    last_active = models.DateTimeField(null=True)
    last_transaction = models.DateTimeField(null=True)
    last_trade = models.DateTimeField(null=True)

    # Lead Status - Using Enum
    lead_status = models.CharField(max_length=20, choices=LeadStatus.choices, default=LeadStatus.NEW)
    call_status = models.CharField(max_length=50, blank=True)

    # Declarations
    DECLARATION_CHOICES = [
        ('terms', 'Terms and Conditions'),
        ('privacy', 'Privacy Policy'),
        ('risk', 'Risk Disclosure'),
        ('ib_agreement', 'IB Agreement')
    ]
    accepted_declarations = models.JSONField(default=list)  # Will store list of accepted declarations with timestamp

    # Add to Customer model:
    email_hash = models.CharField(max_length=64, unique=True, db_index=True)

    REQUIRED_FIELDS = ['first_name', 'last_name']

    class Meta:
        app_label = 'customers'
        db_table = 'customers'
        verbose_name_plural = 'customers'
        permissions = [
            # Base CRUD permissions (auto-generated by Django)
            # view_customer, add_customer, change_customer, delete_customer
            
            # Customer-specific action permissions
            ("assign_customer", "Can assign customers to CRM users"),
            ("manage_customer_status", "Can manage customer status (lead/client/IB)"),
            ("block_customer", "Can block/unblock customer"),
            ("manage_customer_trading_controls", "Can manage customer trading controls"),
            ("manage_customer_transaction_controls", "Can manage customer transaction controls"),
            ("manage_customer_sensitive_data", "Can manage sensitive customer data"),
            ("verify_customer_kyc", "Can verify customer KYC documents"),
            ("manage_customer_ib_status", "Can manage customer IB status"),
            ("export_customer_data", "Can export customer data"),
            ("view_customer_sensitive_fields", "Can view customer sensitive fields"),
            ("approve_customer_changes", "Can approve pending customer changes"),
            ("set_customer_call_status", "Can set customer call status"),
        ]

    # Required for DRF authentication
    @property
    def is_authenticated(self):
        return True

    @property
    def is_active(self):
        return self.auth.is_active if hasattr(self, 'auth') else False

    def save(self, *args, **kwargs):
        # Update email_hash if email field has changed or is being set for the first time
        if self.email and (not self.pk or 
                           not self._meta.model.objects.filter(pk=self.pk).exists() or 
                           not self.email_hash):
            self.email_hash = hashlib.sha256(self.email.lower().encode()).hexdigest()
        super().save(*args, **kwargs)

class CustomerSettings(BaseModel):
    customer = models.OneToOneField('customers.Customer', on_delete=models.CASCADE, related_name='settings')
    
    # Verification Status
    verification_status = models.JSONField(default=dict)
    
    # Controls
    transaction_controls = models.JSONField(default=dict)
    trading_controls = models.JSONField(default=dict)
    notification_preferences = models.JSONField(default=dict)
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if not self.verification_status:
            self.verification_status = {
                "email": {
                    "verified": False,
                    "verifiedAt": None,
                    "lastVerificationSentAt": None
                },
                "phone": {
                    "verified": False,
                    "verifiedAt": None,
                    "lastVerificationSentAt": None
                },
                "mobile": {
                    "verified": False,
                    "verifiedAt": None,
                    "lastVerificationSentAt": None
                }
            }
        if not self.transaction_controls:
            self.transaction_controls = {
                "deposits": {"disabled": False, "reason": None, "disabledAt": None, "disabledBy": None},
                "withdrawals": {"disabled": False, "reason": None, "disabledAt": None, "disabledBy": None},
                "internalTransfers": {"disabled": False, "reason": None, "disabledAt": None, "disabledBy": None}
            }
        if not self.trading_controls:
            self.trading_controls = {
                "trading": {"disabled": False, "reason": None, "disabledAt": None, "disabledBy": None},
                "scalping": {"enabled": False, "enabledAt": None, "enabledBy": None},
                "selfRebate": {"enabled": False, "enabledAt": None, "enabledBy": None}
            }
        if not self.notification_preferences:
            self.notification_preferences = {
                "web": {  # WebSocket notifications
                    "enabled": True,
                    "types": {
                        "ACCOUNT": True,
                        "TRANSACTION": True,
                        "SETTINGS": True,
                        "SECURITY": True,
                        "KYC": True,
                        "SUPPORT": True,
                        "REQUEST": True,
                        "CUSTOMER": True,
                        "NEWS": True,
                        "MARKETING": True
                    },
                    "levels": {
                        "INFO": True,
                        "SUCCESS": True,
                        "WARNING": True,
                        "ERROR": True
                    }
                },
                "web_push": {  # Browser push notifications
                    "enabled": True,
                    "subscriptions": [],  # List of browser push subscriptions (endpoint, keys, etc)
                    "types": {
                        "ACCOUNT": True,
                        "TRANSACTION": True,
                        "SETTINGS": True,
                        "SECURITY": True,
                        "KYC": True,
                        "SUPPORT": True,
                        "REQUEST": True,
                        "CUSTOMER": True,
                        "NEWS": True,
                        "MARKETING": True
                    },
                    "levels": {
                        "WARNING": True,
                        "ERROR": True  # By default, only send important web push notifications
                    }
                },
                "mobile_push": {  # Mobile app push notifications
                    "enabled": True,
                    "devices": [],  # List of mobile device tokens
                    "types": {
                        "ACCOUNT": True,
                        "TRANSACTION": True,
                        "SETTINGS": True,
                        "SECURITY": True,
                        "KYC": True,
                        "SUPPORT": True,
                        "REQUEST": True,
                        "CUSTOMER": True,
                        "NEWS": True,
                        "MARKETING": True
                    },
                    "levels": {
                        "WARNING": True,
                        "ERROR": True  # By default, only send important push notifications
                    }
                },
                "email": {  # Email notifications
                    "security": True,
                    "transactions": True,
                    "accounts": True,
                    "requests": True,
                    "trading": True,
                    "kyc": True,
                    "news": True,
                    "marketing": True,
                    "levels": {
                        "WARNING": True,
                        "ERROR": True  # By default, only send important emails
                    }
                }
            }

    def should_notify(self, notification_type: str, level: str, channel: str = 'web') -> bool:
        """
        Check if a notification should be sent based on customer preferences
        """
        prefs = self.notification_preferences.get(channel, {})
        if not prefs.get('enabled', True):
            return False
            
        # Check for registered devices/subscriptions
        if channel == 'mobile_push' and not prefs.get('devices'):
            return False
        elif channel == 'web_push' and not prefs.get('subscriptions'):
            return False
            
        if channel in ['web', 'web_push', 'mobile_push']:
            type_allowed = prefs.get('types', {}).get(notification_type, True)
            level_allowed = prefs.get('levels', {}).get(level, True)
            return type_allowed and level_allowed
        elif channel == 'email':
            # Email uses different categories
            type_mapping = {
                'ACCOUNT': 'accounts',
                'TRANSACTION': 'transactions',
                'SETTINGS': 'security',
                'SECURITY': 'security',
                'KYC': 'kyc'
            }
            email_category = type_mapping.get(notification_type, 'security')
            category_allowed = prefs.get(email_category, True)
            level_allowed = prefs.get('levels', {}).get(level, True)
            return category_allowed and level_allowed

        return True

    def register_device(self, device_token: str, channel: str = 'mobile_push'):
        """
        Register a mobile device for push notifications
        """
        prefs = self.notification_preferences.get(channel, {})
        devices = prefs.get('devices', [])
        if device_token not in devices:
            devices.append(device_token)
            prefs['devices'] = devices
            self.save()

    def register_web_push(self, subscription_info: dict):
        """
        Register a browser for web push notifications
        subscription_info should contain:
        {
            'endpoint': 'https://push-service.com/...',
            'keys': {
                'p256dh': 'public key',
                'auth': 'auth secret'
            }
        }
        """
        prefs = self.notification_preferences.get('web_push', {})
        subscriptions = prefs.get('subscriptions', [])
        
        # Check if subscription already exists by endpoint
        exists = any(sub['endpoint'] == subscription_info['endpoint'] for sub in subscriptions)
        if not exists:
            subscriptions.append(subscription_info)
            prefs['subscriptions'] = subscriptions
            self.save()

    def unregister_web_push(self, endpoint: str):
        """
        Unregister a browser from web push notifications
        """
        prefs = self.notification_preferences.get('web_push', {})
        subscriptions = prefs.get('subscriptions', [])
        prefs['subscriptions'] = [sub for sub in subscriptions if sub['endpoint'] != endpoint]
        self.save()

    class Meta:
        app_label = 'customers'
        db_table = 'customer_settings'

class CustomerDetail(SensitiveFieldsTrackingMixin, BaseModel):
    customer = models.OneToOneField('customers.Customer', on_delete=models.CASCADE, related_name='details')
    
    # Personal Info - Encrypted sensitive fields
    title = models.CharField(max_length=10, blank=True)
    dob = models.DateField(null=True)
    nationality = models.CharField(max_length=2, blank=True)
    city = models.CharField(max_length=100, blank=True)
    address = models.CharField(max_length=500, blank=True)
    address2 = models.CharField(max_length=500, blank=True)
    gender = models.CharField(max_length=1, blank=True)
    zip_code = models.CharField(max_length=20, blank=True)
    language = models.CharField(max_length=2, default='EN')
    
    # Define sensitive fields for tracking
    sensitive_fields = []
    requires_approval_fields = []
    
    # Referral Info
    referral = models.CharField(
        max_length=20, 
        unique=True, 
        default=generate_referral_code
    )
    register_referral = models.CharField(max_length=100, blank=True)
    register_utm_campaign = models.CharField(max_length=100, blank=True)
    register_ib_id = models.CharField(max_length=100, blank=True)
    register_agreement_id = models.CharField(max_length=100, blank=True)
    register_url = models.CharField(max_length=255, blank=True)
    register_data = models.JSONField(default=dict)
    
    # Financial & Legal
    us_citizen = models.BooleanField(default=False)
    worked_in_financial = models.BooleanField(default=False)
    worked_in_crypto = models.BooleanField(default=False)
    tax_identification_number = models.CharField(max_length=50, blank=True)
    politically_exposed = models.BooleanField(default=False)
    annual_income = models.CharField(max_length=50, blank=True)
    source_of_funds = models.CharField(max_length=50, blank=True)
    fatca = models.BooleanField(default=False)
    
    # Document Details
    doc_type = models.CharField(max_length=50, blank=True)
    document_no = models.CharField(max_length=50, blank=True)
    date_of_issue = models.DateField(null=True)
    date_of_expiry = models.DateField(null=True)
    country_of_issue = models.CharField(max_length=2, blank=True)
    
    # Professional Info
    employment_status = models.CharField(max_length=50, blank=True)
    industry = models.CharField(max_length=100, blank=True)
    profession = models.CharField(max_length=100, blank=True)
    job_title = models.CharField(max_length=100, blank=True)
    employer = models.CharField(max_length=100, blank=True)

    # IB Specific Fields
    have_site = models.CharField(max_length=255, null=True, blank=True)
    ref_other = models.CharField(max_length=255, null=True, blank=True)
    target_countries = models.JSONField(null=True, blank=True)
    get_client = models.CharField(max_length=255, null=True, blank=True)
    expected_clients = models.IntegerField(null=True, blank=True)
    
    # External IDs
    hubspot_id = models.CharField(max_length=100, blank=True)
    old_record_id = models.CharField(max_length=100, blank=True)
    sumsub_app_id = models.CharField(max_length=100, null=True, blank=True)
    sumsub_ins_id = models.CharField(max_length=100, null=True, blank=True)

    client_at = models.DateTimeField(null=True)
    ib_at = models.DateTimeField(null=True)
    lead_at = models.DateTimeField(null=True)
    class Meta:
        app_label = 'customers'
        db_table = 'customer_details'

class CustomerAuth(SensitiveFieldsTrackingMixin, BaseModel):
    customer = models.OneToOneField('customers.Customer', on_delete=models.CASCADE, related_name='auth')
    password = models.CharField(max_length=128)
    last_login = models.DateTimeField(null=True)
    is_active = models.BooleanField(default=True)
    two_factor_enabled = models.BooleanField(default=False)
    two_factor_secret = models.CharField(max_length=32, blank=True)
    two_factor_backup_codes = models.JSONField(default=list)
    webauthn_credentials = models.JSONField(default=list)
    temp_webauthn_challenge = models.CharField(max_length=512, blank=True, null=True)
    webauthn_challenge = models.CharField(max_length=512, blank=True, null=True)
    
    # Password reset fields
    reset_token = models.CharField(max_length=255, blank=True, null=True)
    reset_token_expiry = models.DateTimeField(null=True, blank=True)
    
    # Blocking fields
    blocked = models.BooleanField(default=False)
    blocked_reason = models.TextField(blank=True, null=True)
    blocked_at = models.DateTimeField(null=True, blank=True)
    unblocked_at = models.DateTimeField(null=True, blank=True)
    blocked_by = models.ForeignKey('users.CRMUser', null=True, blank=True, on_delete=models.SET_NULL, related_name='blocked_customers')
    unblocked_by = models.ForeignKey('users.CRMUser', null=True, blank=True, on_delete=models.SET_NULL, related_name='unblocked_customers')
    
    def set_password(self, raw_password):
        self.password = make_password(raw_password)
        self.save()
    
    def check_password(self, raw_password):
        print(f"Checking password: {raw_password} {self.password}")
        return check_password(raw_password, self.password)
    
    class Meta:
        app_label = 'customers'
        db_table = 'customer_auth'
