from django.contrib.auth.models import AbstractUser
from django.db import models
import uuid


def company_logo_upload_path(instance, filename):
    return f'company_logos/{instance.id}/{filename}'


class Company(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=255)
    logo = models.ImageField(upload_to=company_logo_upload_path, blank=True, null=True)
    establishment_date = models.DateField()
    owner_name = models.CharField(max_length=255)
    owner_email = models.EmailField()
    owner_phone = models.CharField(max_length=20)
    address = models.TextField(blank=True)
    is_approved = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True, help_text="Unchecked = paused by super admin; company users cannot log in.")
    db_name = models.CharField(max_length=64, blank=True, help_text="Tenant database name, auto-generated on approval.")
    is_provisioned = models.BooleanField(default=False, help_text="Whether the tenant database has been created and migrated.")
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'companies'
        verbose_name_plural = 'Companies'
        ordering = ['-created_at']

    def __str__(self):
        return self.name

    @property
    def db_alias(self):
        """The Django DATABASES alias this company's data lives in."""
        return self.db_name if self.db_name else "default"


class Branch(models.Model):
    """A physical branch / outlet of a registered company.

    Lives in the shared (default) database next to Company and CustomUser so that
    users can be assigned to a branch. Tenant tables (sales, purchases, stock,
    expenses, payroll ...) reference a branch by id with db_constraint=False,
    exactly like they already reference the company.
    """
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='branches')
    name = models.CharField(max_length=120)
    code = models.CharField(max_length=20, blank=True, help_text="Short code, e.g. MAIN, UTR, CTG.")
    phone = models.CharField(max_length=20, blank=True)
    email = models.EmailField(blank=True)
    address = models.TextField(blank=True)
    manager_name = models.CharField(max_length=120, blank=True)
    is_main = models.BooleanField(default=False, help_text="The head office / main branch of the company.")
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'branches'
        ordering = ['-is_main', 'name']
        unique_together = [('company', 'name')]

    def __str__(self):
        return self.name


class CustomUser(AbstractUser):
    ROLE_CHOICES = (
        ('superadmin', 'Super Admin'),
        ('admin', 'Admin'),
        ('sales_person', 'Sales Person'),
    )
    role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='sales_person')
    company = models.ForeignKey(Company, on_delete=models.CASCADE, null=True, blank=True, related_name='users')
    phone = models.CharField(max_length=20, blank=True)
    branch = models.ForeignKey(
        Branch, on_delete=models.SET_NULL, null=True, blank=True, related_name='users',
        help_text="Branch this user works in. Sales people only see and sell from their own branch.",
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'custom_users'
        ordering = ['-created_at']

    def __str__(self):
        return f"{self.username} ({self.get_role_display()})"

    @property
    def is_superadmin(self):
        return self.role == 'superadmin' and self.is_superuser


class PlatformBankAccount(models.Model):
    """A bank account the super admin publishes so companies know where to pay."""
    bank_name = models.CharField(max_length=150)
    account_holder_name = models.CharField(max_length=150)
    account_number = models.CharField(max_length=50)
    branch_name = models.CharField(max_length=150, blank=True)
    routing_number = models.CharField(max_length=50, blank=True)
    swift_code = models.CharField(max_length=30, blank=True)
    instructions = models.TextField(blank=True, help_text="Any note shown to companies about how to pay to this account.")
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'platform_bank_accounts'
        ordering = ['-created_at']
        verbose_name = 'Bank Account'
        verbose_name_plural = 'Bank Accounts'

    def __str__(self):
        return f"{self.bank_name} - {self.account_number}"


class PlatformMobileBanking(models.Model):
    """A mobile banking (bKash/Nagad/Rocket/etc.) number the super admin publishes."""
    PROVIDER_CHOICES = (
        ('bkash', 'bKash'),
        ('nagad', 'Nagad'),
        ('rocket', 'Rocket'),
        ('upay', 'Upay'),
        ('other', 'Other'),
    )
    ACCOUNT_TYPE_CHOICES = (
        ('personal', 'Personal'),
        ('agent', 'Agent'),
        ('merchant', 'Merchant'),
    )
    provider = models.CharField(max_length=20, choices=PROVIDER_CHOICES)
    provider_other_name = models.CharField(max_length=50, blank=True, help_text="Only needed when provider is 'Other'.")
    account_number = models.CharField(max_length=30)
    account_type = models.CharField(max_length=20, choices=ACCOUNT_TYPE_CHOICES, default='personal')
    instructions = models.TextField(blank=True, help_text="Any note shown to companies about how to send money here.")
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'platform_mobile_banking'
        ordering = ['-created_at']
        verbose_name = 'Mobile Banking Number'
        verbose_name_plural = 'Mobile Banking Numbers'

    def __str__(self):
        return f"{self.get_provider_display()} - {self.account_number}"

    @property
    def display_provider(self):
        if self.provider == 'other' and self.provider_other_name:
            return self.provider_other_name
        return self.get_provider_display()


class CompanyPayment(models.Model):
    """A payment received from a registered company, recorded by the super admin."""
    METHOD_CHOICES = (
        ('bank', 'Bank Transfer'),
        ('mobile_banking', 'Mobile Banking'),
    )
    STATUS_CHOICES = (
        ('pending', 'Pending'),
        ('verified', 'Verified'),
        ('rejected', 'Rejected'),
    )
    company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='platform_payments')
    amount = models.DecimalField(max_digits=12, decimal_places=2)
    method = models.CharField(max_length=20, choices=METHOD_CHOICES)
    bank_account = models.ForeignKey(PlatformBankAccount, on_delete=models.SET_NULL, null=True, blank=True, related_name='payments')
    mobile_account = models.ForeignKey(PlatformMobileBanking, on_delete=models.SET_NULL, null=True, blank=True, related_name='payments')
    transaction_id = models.CharField(max_length=100, blank=True, help_text="Sender's transaction/reference ID.")
    payment_date = models.DateField()
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
    note = models.CharField(max_length=255, blank=True)
    recorded_by = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True, blank=True, related_name='recorded_payments')
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'company_payments'
        ordering = ['-payment_date', '-created_at']
        verbose_name = 'Company Payment'
        verbose_name_plural = 'Company Payments'

    def __str__(self):
        return f"{self.company.name} - {self.amount} ({self.get_status_display()})"

    @property
    def method_detail(self):
        if self.method == 'bank' and self.bank_account_id:
            return str(self.bank_account)
        if self.method == 'mobile_banking' and self.mobile_account_id:
            return str(self.mobile_account)
        return self.get_method_display()
