import json
import logging
import re
from odoo import http
from odoo.http import request
from odoo.addons.encoach_api.controllers.base import (
    jwt_required, _json_response, _error_response, _get_json_body, _paginate
)

_logger = logging.getLogger(__name__)

EMAIL_RE = re.compile(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$')


class EncoachEntityOnboardController(http.Controller):

    # ------------------------------------------------------------------
    # POST /api/entity/students/validate-csv
    # ------------------------------------------------------------------
    @http.route('/api/entity/students/validate-csv', type='http', auth='none',
                methods=['POST'], csrf=False)
    @jwt_required
    def validate_csv(self, **kw):
        try:
            uploaded = request.httprequest.files.get('file')
            if not uploaded:
                return _error_response('CSV file is required (multipart field "file")', 400)

            raw = uploaded.read()
            from odoo.addons.encoach_entity_onboard.services.csv_parser import CsvParser
            parser = CsvParser()
            result = parser.validate(raw)

            valid_rows = result['valid_rows']
            parse_errors = result['errors']

            row_errors = []
            for err in parse_errors:
                row_errors.append({'row': 0, 'field': '', 'message': err})

            User = request.env['res.users'].sudo()
            dedup_errors = []
            for idx, row in enumerate(valid_rows):
                email = row.get('email', '')
                if email and not EMAIL_RE.match(email):
                    row_errors.append({
                        'row': idx + 2,
                        'field': 'email',
                        'message': f"Invalid email format: {email}",
                    })
                    continue

                if email:
                    existing = User.search([('login', '=', email)], limit=1)
                    if existing:
                        dedup_errors.append({
                            'row': idx + 2,
                            'field': 'email',
                            'message': f"Duplicate email already exists in DB: {email}",
                        })

            all_errors = row_errors + dedup_errors
            error_count = len(all_errors)
            truly_valid = [
                r for i, r in enumerate(valid_rows)
                if not any(e['row'] == i + 2 for e in all_errors)
            ]

            preview = truly_valid[:5]

            return _json_response({
                'valid_count': len(truly_valid),
                'error_count': error_count,
                'errors': all_errors,
                'preview': preview,
            })

        except Exception as e:
            _logger.exception('validate_csv failed')
            return _error_response(str(e), 500)

    # ------------------------------------------------------------------
    # POST /api/entity/students/bulk-create
    # ------------------------------------------------------------------
    @http.route('/api/entity/students/bulk-create', type='http', auth='none',
                methods=['POST'], csrf=False)
    @jwt_required
    def bulk_create(self, **kw):
        try:
            body = _get_json_body()
            rows = body.get('rows', [])
            entity_id = body.get('entity_id')

            if not rows:
                return _error_response('rows array is required', 400)
            if not entity_id:
                return _error_response('entity_id is required', 400)

            entity_id = int(entity_id)
            Entity = request.env['encoach.entity'].sudo()
            entity = Entity.browse(entity_id)
            if not entity.exists():
                return _error_response('Entity not found', 404)

            from odoo.addons.encoach_entity_onboard.services.credential_service import CredentialService
            service = CredentialService()
            created_users = service.create_accounts(request.env, rows, entity_id)

            return _json_response({
                'created_count': len(created_users),
                'user_ids': created_users.ids,
            }, 201)

        except Exception as e:
            _logger.exception('bulk_create failed')
            return _error_response(str(e), 500)

    # ------------------------------------------------------------------
    # POST /api/entity/students/send-credentials
    # ------------------------------------------------------------------
    @http.route('/api/entity/students/send-credentials', type='http', auth='none',
                methods=['POST'], csrf=False)
    @jwt_required
    def send_credentials(self, **kw):
        try:
            body = _get_json_body()
            user_ids = body.get('user_ids', [])
            if not user_ids:
                return _error_response('user_ids array is required', 400)

            user_ids = [int(uid) for uid in user_ids]

            from odoo.addons.encoach_entity_onboard.services.credential_service import CredentialService
            service = CredentialService()
            service.send_credentials(request.env, user_ids)

            return _json_response({'sent_count': len(user_ids)})

        except Exception as e:
            _logger.exception('send_credentials failed')
            return _error_response(str(e), 500)

    # ------------------------------------------------------------------
    # POST /api/entity/students/<int:student_id>/resend-credentials
    # ------------------------------------------------------------------
    @http.route('/api/entity/students/<int:student_id>/resend-credentials',
                type='http', auth='none', methods=['POST'], csrf=False)
    @jwt_required
    def resend_credentials(self, student_id, **kw):
        try:
            User = request.env['res.users'].sudo()
            user = User.browse(student_id)
            if not user.exists():
                return _error_response('Student not found', 404)

            from odoo.addons.encoach_entity_onboard.services.credential_service import CredentialService
            service = CredentialService()
            service.resend_credentials(request.env, student_id)

            return _json_response({'sent': True})

        except Exception as e:
            _logger.exception('resend_credentials failed')
            return _error_response(str(e), 500)

    # ------------------------------------------------------------------
    # POST /api/entity/students/resend-all-pending
    # ------------------------------------------------------------------
    @http.route('/api/entity/students/resend-all-pending', type='http', auth='none',
                methods=['POST'], csrf=False)
    @jwt_required
    def resend_all_pending(self, **kw):
        try:
            user = request.env.user.sudo()
            domain = [
                ('first_login', '=', True),
                ('account_source', '=', 'entity_bulk_upload'),
            ]

            if user.entity_ids:
                domain.append(('entity_ids', 'in', user.entity_ids.ids))

            User = request.env['res.users'].sudo()
            pending_users = User.search(domain)

            if not pending_users:
                return _json_response({'sent_count': 0})

            from odoo.addons.encoach_entity_onboard.services.credential_service import CredentialService
            service = CredentialService()
            service.send_credentials(request.env, pending_users.ids)

            return _json_response({'sent_count': len(pending_users)})

        except Exception as e:
            _logger.exception('resend_all_pending failed')
            return _error_response(str(e), 500)

    # ------------------------------------------------------------------
    # POST /api/entity/students/sis-import
    # ------------------------------------------------------------------
    @http.route('/api/entity/students/sis-import', type='http', auth='none',
                methods=['POST'], csrf=False)
    @jwt_required
    def sis_import(self, **kw):
        try:
            sis_data = None
            uploaded = request.httprequest.files.get('file')
            if uploaded:
                raw = uploaded.read()
                try:
                    sis_data = json.loads(raw)
                except (json.JSONDecodeError, TypeError):
                    return _error_response('Invalid JSON file', 400)
            else:
                body = _get_json_body()
                sis_data = body.get('sis_data', [])

            if not sis_data or not isinstance(sis_data, list):
                return _error_response('sis_data must be a non-empty JSON array', 400)

            user = request.env.user.sudo()
            entity_id = None
            if user.entity_ids:
                entity_id = user.entity_ids[0].id

            User = request.env['res.users'].sudo()
            imported_count = 0
            updated_count = 0
            errors = []

            for idx, record in enumerate(sis_data):
                email = (record.get('email') or '').strip()
                name = (record.get('name') or '').strip()
                national_id = (record.get('national_id') or '').strip()
                phone = (record.get('phone') or '').strip()

                if not email or not name:
                    errors.append({
                        'index': idx,
                        'message': 'name and email are required',
                    })
                    continue

                if not EMAIL_RE.match(email):
                    errors.append({
                        'index': idx,
                        'message': f'Invalid email: {email}',
                    })
                    continue

                try:
                    existing = User.search([('login', '=', email)], limit=1)
                    if existing:
                        update_vals = {'name': name}
                        if phone:
                            update_vals['phone'] = phone
                        existing.write(update_vals)
                        if entity_id and hasattr(existing, 'entity_ids'):
                            if entity_id not in existing.entity_ids.ids:
                                existing.write({'entity_ids': [(4, entity_id)]})
                        updated_count += 1
                    else:
                        create_vals = {
                            'name': name,
                            'login': email,
                            'email': email,
                            'phone': phone,
                            'password': national_id or email.split('@')[0],
                            'account_source': 'entity_bulk_upload',
                            'account_status': 'activated',
                        }
                        if entity_id:
                            create_vals['entity_id'] = entity_id
                        User.create(create_vals)
                        imported_count += 1
                except Exception as rec_err:
                    errors.append({
                        'index': idx,
                        'message': str(rec_err),
                    })
                    _logger.warning('SIS import error for row %d: %s', idx, rec_err)

            return _json_response({
                'imported_count': imported_count,
                'updated_count': updated_count,
                'errors': errors,
            })

        except Exception as e:
            _logger.exception('sis_import failed')
            return _error_response(str(e), 500)
