# -*- coding: utf-8 -*-
import string
import random
import logging
from odoo import models, fields, api, registry, SUPERUSER_ID
from odoo.exceptions import UserError
from odoo.service import db
from odoo.tools import config

_logger = logging.getLogger(__name__)

class SaasRestaurant(models.Model):
    _name = 'saas.restaurant'
    _inherit = ['mail.thread', 'mail.activity.mixin']
    _description = 'Dine360 SaaS Restaurant Tenant'

    name = fields.Char(string='Restaurant Name', required=True, tracking=True)
    owner_name = fields.Char(string='Owner Name', required=True, tracking=True)
    email = fields.Char(string='Owner Email', required=True, tracking=True)
    phone = fields.Char(string='Phone')
    street = fields.Char(string='Street')
    city = fields.Char(string='City')
    country_id = fields.Many2one('res.country', string='Country')
    
    plan_id = fields.Many2one('saas.plan', string='Subscription Plan', required=True, tracking=True)
    billing_cycle = fields.Selection([
        ('monthly', 'Monthly Billing'),
        ('yearly', 'Annual Billing')
    ], string='Billing Cycle', default='monthly', required=True)
    
    database_name = fields.Char(string='PostgreSQL DB Name', readonly=True, copy=False)
    subdomain = fields.Char(string='Subdomain', readonly=True, copy=False)
    
    status = fields.Selection([
        ('draft', 'Draft'),
        ('active', 'Active'),
        ('suspended', 'Suspended'),
        ('expired', 'Expired')
    ], string='Status', default='draft', required=True, tracking=True)
    
    start_date = fields.Date(string='Start Date', default=fields.Date.context_today)
    expiry_date = fields.Date(string='Expiry Date', required=True)
    
    currency_id = fields.Many2one('res.currency', string='Base Currency')
    timezone = fields.Char(string='Timezone', default='America/New_York')
    logo = fields.Binary(string='Restaurant Logo')

    _sql_constraints = [
        ('unique_subdomain', 'unique(subdomain)', 'This subdomain is already taken!'),
        ('unique_database_name', 'unique(database_name)', 'This database name is already registered!')
    ]

    @api.model
    def create(self, vals):
        # Generate subdomain and database name from restaurant name
        name_slug = ''.join(c for c in vals.get('name', '').lower() if c.isalnum())
        if not name_slug:
            name_slug = 'restaurant'
        
        # Ensure uniqueness
        base_slug = name_slug
        counter = 1
        while self.env['saas.restaurant'].search([('subdomain', '=', f"{name_slug}.dine360.com")]):
            name_slug = f"{base_slug}{counter}"
            counter += 1
            
        vals['subdomain'] = f"{name_slug}.dine360.com"
        vals['database_name'] = f"dine360_restaurant_{name_slug}"
        return super(SaasRestaurant, self).create(vals)

    def action_create_database(self):
        self.ensure_one()
        if self.database_name in db.list_dbs():
            raise UserError(f"Database {self.database_name} already exists in PostgreSQL!")

        # 1. Provision PostgreSQL database
        admin_pass = ''.join(random.choices(string.ascii_letters + string.digits, k=12))
        
        try:
            _logger.info(f"Creating database {self.database_name}...")
            db.exp_create_database(
                self.database_name, 
                False, 
                'en_US', 
                user_password=admin_pass, 
                login=self.email,
                country_code=self.country_id.code if self.country_id else None,
                phone=self.phone
            )
            _logger.info(f"Database {self.database_name} created successfully.")
        except Exception as e:
            raise UserError(f"PostgreSQL database creation failed: {str(e)}")

        # 2. Boot environment on new database and install modules
        tenant_registry = registry(self.database_name)
        modules_to_install = [
            'base', 'contacts', 'sale', 'stock', 'purchase', 
            'account', 'point_of_sale', 'hr', 'restaurant'
        ]
        
        try:
            _logger.info(f"Installing base modules on {self.database_name}...")
            with tenant_registry.cursor() as cr:
                env = api.Environment(cr, SUPERUSER_ID, {})
                module_objs = env['ir.module.module'].search([('name', 'in', modules_to_install)])
                module_objs.write({'state': 'to install'})
                cr.commit()
                # Run immediate install for Odoo base
                module_objs.button_immediate_install()
                cr.commit()
                
            _logger.info("Base modules installed successfully. Configuring company...")
            
            # 3. Configure Company & Admin User inside the new database
            with tenant_registry.cursor() as cr:
                env = api.Environment(cr, SUPERUSER_ID, {})
                
                # Company setup
                company = env['res.company'].search([], limit=1)
                company.write({
                    'name': self.name,
                    'phone': self.phone,
                    'email': self.email,
                    'street': self.street,
                    'city': self.city,
                    'country_id': self.country_id.id if self.country_id else False,
                    'currency_id': self.currency_id.id if self.currency_id else False,
                    'logo': self.logo,
                })
                
                # Admin user setup (ID 2 is usually admin)
                admin_user = env['res.users'].browse(2)
                admin_user.write({
                    'name': self.owner_name,
                    'login': self.email,
                    'email': self.email,
                    'password': admin_pass,
                })
                
                # Set timezone
                admin_user.partner_id.tz = self.timezone
                cr.commit()

        except Exception as e:
            # If provisioning fails midway, drop the database to allow clean retry
            _logger.error(f"Failed configuring tenant registry: {str(e)}")
            try:
                db.exp_drop(self.database_name)
            except Exception:
                pass
            raise UserError(f"Database provisioning / module installation failed: {str(e)}")

        self.status = 'active'
        
        # Send Welcome Email
        template = self.env.ref('dine360_saas_master.saas_welcome_email_template', raise_if_not_found=False)
        if template:
            # Context for temporary password
            self.with_context(temp_password=admin_pass).message_post_with_source(
                source_ref=template,
                subtype_xmlid='mail.mt_comment'
            )
            
        return True

    def action_suspend(self):
        self.ensure_one()
        # Suspend by disabling login in target database
        tenant_registry = registry(self.database_name)
        try:
            with tenant_registry.cursor() as cr:
                env = api.Environment(cr, SUPERUSER_ID, {})
                # Disable all users except superuser
                users = env['res.users'].search([('id', '!=', SUPERUSER_ID)])
                users.write({'active': False})
                cr.commit()
            self.status = 'suspended'
        except Exception as e:
            raise UserError(f"Failed to suspend database users: {str(e)}")

    def action_activate(self):
        self.ensure_one()
        # Activate by re-enabling login in target database
        tenant_registry = registry(self.database_name)
        try:
            with tenant_registry.cursor() as cr:
                env = api.Environment(cr, SUPERUSER_ID, {})
                # Enable all users
                users = env['res.users'].search([('active', '=', False), ('id', '!=', SUPERUSER_ID)])
                users.write({'active': True})
                cr.commit()
            self.status = 'active'
        except Exception as e:
            raise UserError(f"Failed to activate database users: {str(e)}")

    @api.model
    def cron_check_subscriptions(self):
        """ Runs nightly to find expired accounts and enforce subscription plan limits """
        today = fields.Date.context_today(self)
        expired_tenants = self.search([('expiry_date', '<', today), ('status', '=', 'active')])
        for tenant in expired_tenants:
            tenant.status = 'expired'
            tenant.action_suspend()
            
        # Enforcement check for limits
        active_tenants = self.search([('status', '=', 'active')])
        for tenant in active_tenants:
            plan = tenant.plan_id
            tenant_registry = registry(tenant.database_name)
            try:
                with tenant_registry.cursor() as cr:
                    env = api.Environment(cr, SUPERUSER_ID, {})
                    
                    # 1. Count active users
                    user_count = env['res.users'].search_count([('active', '=', True), ('id', '!=', SUPERUSER_ID)])
                    # 2. Count active POS terminals
                    pos_count = env['pos.config'].search_count([('active', '=', True)])
                    
                    # Log warnings/limits
                    if plan.max_users > 0 and user_count > plan.max_users:
                        _logger.warning(f"Tenant {tenant.name} exceeds user limit: {user_count}/{plan.max_users}")
                        # Auto suspend or flag
                    if plan.max_pos > 0 and pos_count > plan.max_pos:
                        _logger.warning(f"Tenant {tenant.name} exceeds POS limit: {pos_count}/{plan.max_pos}")
            except Exception as e:
                _logger.error(f"Error checking limits for {tenant.database_name}: {str(e)}")
