"""
Admin Users API Routes - Admin blueprint

Migrated from app.py as part of the blueprint refactoring.
Contains API routes for AI-powered user parsing and bulk user creation.
"""

import json
import logging
import os
import re
import secrets
import string
import tempfile
from datetime import datetime

from flask import jsonify, request
from flask_login import current_user, login_required
from werkzeug.security import generate_password_hash

from database import SessionLocal, User, Company, SystemRole, CompanyRole, UserCompanyPermissions, UserCompany
from utils.decorators import role_required
import gemini_service
from . import bp

logger = logging.getLogger(__name__)


# ============================================================
# AI PROMPTS FOR USER PARSING
# ============================================================

AI_USER_PARSE_PROMPT = """Jesteś asystentem systemu NordaBiz pomagającym administratorowi tworzyć konta użytkowników.

ZADANIE:
Przeanalizuj podany tekst i wyodrębnij informacje o użytkownikach.

DANE WEJŚCIOWE:
```
{input_text}
```

DOSTĘPNE FIRMY W SYSTEMIE (id: nazwa):
{companies_json}

INSTRUKCJE:
1. Wyodrębnij każdą osobę/użytkownika z tekstu
2. Dla każdego użytkownika zidentyfikuj:
   - email (WYMAGANY - jeśli brak prawidłowego emaila, pomiń użytkownika)
   - imię i nazwisko (jeśli dostępne)
   - firma (dopasuj do listy dostępnych firm po nazwie, nawet częściowej)
   - rola: jeśli tekst zawiera słowa "admin", "administrator", "zarząd" przy danej osobie - ustaw role na "ADMIN", w przeciwnym razie "MEMBER"
3. Jeśli email jest niepoprawny (brak @), dodaj ostrzeżenie
4. Jeśli firma nie pasuje do żadnej z listy, ustaw company_id na null

ZWRÓĆ TYLKO CZYSTY JSON w dokładnie takim formacie (bez żadnego tekstu przed ani po):
{{
    "analysis": "Krótki opis znalezionych danych (1-2 zdania po polsku)",
    "users": [
        {{
            "email": "adres@email.pl",
            "name": "Imię Nazwisko lub null",
            "company_id": 123,
            "company_name": "Nazwa dopasowanej firmy lub null",
            "role": "MEMBER",
            "warnings": []
        }}
    ]
}}"""

AI_USER_IMAGE_PROMPT = """Jesteś asystentem systemu NordaBiz pomagającym administratorowi tworzyć konta użytkowników.

ZADANIE:
Przeanalizuj ten obraz (screenshot) i wyodrębnij informacje o użytkownikach.
Szukaj: adresów email, imion i nazwisk, nazw firm, ról (admin/user).

DOSTĘPNE FIRMY W SYSTEMIE (id: nazwa):
{companies_json}

INSTRUKCJE:
1. Przeczytaj cały tekst widoczny na obrazie
2. Wyodrębnij każdą osobę/użytkownika
3. Dla każdego użytkownika zidentyfikuj:
   - email (WYMAGANY - jeśli brak, pomiń)
   - imię i nazwisko
   - firma (dopasuj do listy)
   - rola: admin lub zwykły użytkownik
4. Jeśli email jest nieczytelny lub niepoprawny, dodaj ostrzeżenie

ZWRÓĆ TYLKO CZYSTY JSON w dokładnie takim formacie (bez żadnego tekstu przed ani po):
{{
    "analysis": "Krótki opis co widzisz na obrazie (1-2 zdania po polsku)",
    "users": [
        {{
            "email": "adres@email.pl",
            "name": "Imię Nazwisko lub null",
            "company_id": 123,
            "company_name": "Nazwa dopasowanej firmy lub null",
            "role": "MEMBER",
            "warnings": []
        }}
    ]
}}"""


# ============================================================
# API ROUTES
# ============================================================

@bp.route('/users-api/ai-parse', methods=['POST'])
@login_required
@role_required(SystemRole.ADMIN)
def admin_users_ai_parse():
    """Parse text or image with AI to extract user data."""
    db = SessionLocal()
    try:
        # Get list of companies for AI context
        companies = db.query(Company).order_by(Company.name).all()
        companies_json = "\n".join([f"{c.id}: {c.name}" for c in companies])

        # Check input type
        input_type = request.form.get('input_type') or (request.get_json() or {}).get('input_type', 'text')

        if input_type == 'image':
            # Handle image upload
            if 'file' not in request.files:
                return jsonify({'success': False, 'error': 'Brak pliku obrazu'}), 400

            file = request.files['file']
            if file.filename == '':
                return jsonify({'success': False, 'error': 'Nie wybrano pliku'}), 400

            # Validate file type
            allowed_extensions = {'png', 'jpg', 'jpeg', 'gif', 'webp'}
            ext = file.filename.rsplit('.', 1)[-1].lower() if '.' in file.filename else ''
            if ext not in allowed_extensions:
                return jsonify({'success': False, 'error': 'Dozwolone formaty: PNG, JPG, JPEG, GIF, WEBP'}), 400

            # Save temp file
            with tempfile.NamedTemporaryFile(delete=False, suffix=f'.{ext}') as tmp:
                file.save(tmp.name)
                temp_path = tmp.name

            try:
                # Get Gemini service and analyze image
                service = gemini_service.get_gemini_service()
                prompt = AI_USER_IMAGE_PROMPT.format(companies_json=companies_json)
                ai_response = service.analyze_image(temp_path, prompt)
            finally:
                # Clean up temp file
                if os.path.exists(temp_path):
                    os.unlink(temp_path)

        else:
            # Handle text input
            data = request.get_json() or {}
            content = data.get('content', '').strip()

            if not content:
                return jsonify({'success': False, 'error': 'Brak treści do analizy'}), 400

            # Get Gemini service and analyze text
            service = gemini_service.get_gemini_service()
            prompt = AI_USER_PARSE_PROMPT.format(
                input_text=content,
                companies_json=companies_json
            )
            ai_response = service.generate_text(
                prompt=prompt,
                feature='ai_user_parse',
                user_id=current_user.id,
                temperature=0.3  # Lower temperature for more consistent JSON output
            )

        # Parse AI response as JSON
        # Try to extract JSON from response (handle potential markdown code blocks)
        json_match = re.search(r'\{[\s\S]*\}', ai_response)
        if not json_match:
            logger.error(f"AI response not valid JSON: {ai_response[:500]}")
            return jsonify({
                'success': False,
                'error': 'AI nie zwróciło prawidłowej odpowiedzi. Spróbuj ponownie.'
            }), 500

        try:
            parsed = json.loads(json_match.group())
        except json.JSONDecodeError as e:
            logger.error(f"JSON parse error: {e}, response: {ai_response[:500]}")
            return jsonify({
                'success': False,
                'error': 'Błąd parsowania odpowiedzi AI. Spróbuj ponownie.'
            }), 500

        # Check for duplicate emails in database
        proposed_users = parsed.get('users', [])
        existing_emails = []

        for user in proposed_users:
            email = user.get('email', '').strip().lower()
            if email:
                existing = db.query(User).filter(User.email == email).first()
                if existing:
                    existing_emails.append(email)
                    user['warnings'] = user.get('warnings', []) + [f'Email już istnieje w systemie']

        logger.info(f"Admin {current_user.email} used AI to parse users: {len(proposed_users)} found")

        return jsonify({
            'success': True,
            'ai_response': parsed.get('analysis', 'Analiza zakończona'),
            'proposed_users': proposed_users,
            'duplicate_emails': existing_emails
        })

    except Exception as e:
        logger.error(f"Error in AI user parse: {e}")
        return jsonify({'success': False, 'error': f'Błąd: {str(e)}'}), 500
    finally:
        db.close()


@bp.route('/users-api/bulk-create', methods=['POST'])
@login_required
@role_required(SystemRole.ADMIN)
def admin_users_bulk_create():
    """Create multiple users from confirmed proposals."""
    db = SessionLocal()
    try:
        data = request.get_json() or {}
        users_to_create = data.get('users', [])

        if not users_to_create:
            return jsonify({'success': False, 'error': 'Brak użytkowników do utworzenia'}), 400

        created = []
        failed = []

        password_chars = string.ascii_letters + string.digits + "!@#$%^&*"

        for user_data in users_to_create:
            email = user_data.get('email', '').strip().lower()

            if not email:
                failed.append({'email': email or 'brak', 'error': 'Brak adresu email'})
                continue

            # Check if email already exists
            existing = db.query(User).filter(User.email == email).first()
            if existing:
                failed.append({'email': email, 'error': 'Email już istnieje'})
                continue

            # Validate company_id if provided
            company_id = user_data.get('company_id')
            if company_id:
                company = db.query(Company).filter(Company.id == company_id).first()
                if not company:
                    company_id = None  # Reset if company doesn't exist

            # Generate password
            generated_password = ''.join(secrets.choice(password_chars) for _ in range(16))
            password_hash = generate_password_hash(generated_password, method='pbkdf2:sha256')

            # Create user
            try:
                new_user = User(
                    email=email,
                    password_hash=password_hash,
                    name=user_data.get('name', '').strip() or None,
                    company_id=company_id,
                    is_verified=True,
                    is_active=True
                )
                db.add(new_user)
                # Set role based on AI parse result
                ai_role = user_data.get('role', 'MEMBER')
                try:
                    new_user.set_role(SystemRole[ai_role])
                except KeyError:
                    new_user.set_role(SystemRole.MEMBER)
                db.flush()  # Get the ID

                created.append({
                    'email': email,
                    'user_id': new_user.id,
                    'name': new_user.name,
                    'generated_password': generated_password
                })

            except Exception as e:
                failed.append({'email': email, 'error': str(e)})

        # Commit all successful creates
        if created:
            db.commit()
            logger.info(f"Admin {current_user.email} bulk created {len(created)} users via AI")

        return jsonify({
            'success': True,
            'created': created,
            'failed': failed,
            'message': f'Utworzono {len(created)} użytkowników' + (f', {len(failed)} błędów' if failed else '')
        })

    except Exception as e:
        db.rollback()
        logger.error(f"Error in bulk user create: {e}")
        return jsonify({'success': False, 'error': f'Błąd: {str(e)}'}), 500
    finally:
        db.close()


@bp.route('/users-api/change-role', methods=['POST'])
@login_required
@role_required(SystemRole.ADMIN)
def admin_users_change_role():
    """Change user's system role."""
    db = SessionLocal()
    try:
        data = request.get_json() or {}
        user_id = data.get('user_id')
        new_role = data.get('role')

        if not user_id or not new_role:
            return jsonify({'success': False, 'error': 'Brak wymaganych danych'}), 400

        # Validate role
        valid_roles = ['UNAFFILIATED', 'MEMBER', 'EMPLOYEE', 'MANAGER', 'OFFICE_MANAGER', 'ADMIN']
        if new_role not in valid_roles:
            return jsonify({'success': False, 'error': f'Nieprawidłowa rola: {new_role}'}), 400

        # Get user
        user = db.query(User).filter(User.id == user_id).first()
        if not user:
            return jsonify({'success': False, 'error': 'Użytkownik nie znaleziony'}), 404

        # Prevent self-demotion from admin
        if user.id == current_user.id and new_role != 'ADMIN':
            return jsonify({'success': False, 'error': 'Nie możesz odebrać sobie uprawnień administratora'}), 400

        old_role = user.role
        user.set_role(SystemRole[new_role])

        # Note: company_role is now managed independently via change-company-role endpoint

        # Create default permissions for EMPLOYEE if they have a company
        if new_role == 'EMPLOYEE' and user.company_id:
            existing_perms = db.query(UserCompanyPermissions).filter_by(
                user_id=user.id,
                company_id=user.company_id
            ).first()

            if not existing_perms:
                perms = UserCompanyPermissions(
                    user_id=user.id,
                    company_id=user.company_id,
                    granted_by_id=current_user.id
                )
                db.add(perms)

        db.commit()

        logger.info(f"Admin {current_user.email} changed role for user {user.email}: {old_role} -> {new_role}")

        return jsonify({
            'success': True,
            'message': f'Rola zmieniona na {new_role}',
            'user_id': user.id,
            'old_role': old_role,
            'new_role': new_role
        })

    except Exception as e:
        db.rollback()
        logger.error(f"Error changing user role: {e}")
        return jsonify({'success': False, 'error': f'Błąd: {str(e)}'}), 500
    finally:
        db.close()


@bp.route('/users-api/roles', methods=['GET'])
@login_required
@role_required(SystemRole.ADMIN)
def admin_users_get_roles():
    """Get list of available roles for dropdown."""
    roles = [
        {'value': 'UNAFFILIATED', 'label': 'Niezrzeszony', 'description': 'Firma spoza Izby'},
        {'value': 'MEMBER', 'label': 'Członek', 'description': 'Członek Norda bez firmy'},
        {'value': 'EMPLOYEE', 'label': 'Pracownik', 'description': 'Pracownik firmy członkowskiej'},
        {'value': 'MANAGER', 'label': 'Kadra Zarządzająca', 'description': 'Pełna kontrola firmy'},
        {'value': 'OFFICE_MANAGER', 'label': 'Kierownik Biura', 'description': 'Panel admina bez użytkowników'},
        {'value': 'ADMIN', 'label': 'Administrator', 'description': 'Pełne prawa'},
    ]

    return jsonify({'success': True, 'roles': roles})


@bp.route('/users-api/change-company-role', methods=['POST'])
@login_required
@role_required(SystemRole.OFFICE_MANAGER)
def admin_users_change_company_role():
    """Change user's company role (portal permissions for company profile)."""
    db = SessionLocal()
    try:
        data = request.get_json() or {}
        user_id = data.get('user_id')
        new_role = data.get('company_role')

        if not user_id or not new_role:
            return jsonify({'success': False, 'error': 'Brak wymaganych danych'}), 400

        valid_roles = ['NONE', 'VIEWER', 'EMPLOYEE', 'MANAGER']
        if new_role not in valid_roles:
            return jsonify({'success': False, 'error': f'Nieprawidłowa rola: {new_role}'}), 400

        user = db.query(User).filter(User.id == user_id).first()
        if not user:
            return jsonify({'success': False, 'error': 'Użytkownik nie znaleziony'}), 404

        old_role = user.company_role
        user.company_role = new_role

        # Sync to user_companies table
        if user.company_id:
            uc = db.query(UserCompany).filter_by(
                user_id=user.id, company_id=user.company_id
            ).first()
            if uc:
                uc.role = new_role
                uc.updated_at = datetime.now()

        db.commit()
        logger.info(f"Admin {current_user.email} changed company_role for user {user.email}: {old_role} -> {new_role}")

        return jsonify({
            'success': True,
            'message': f'Uprawnienia firmowe zmienione na {new_role}',
            'user_id': user.id,
            'old_role': old_role,
            'new_role': new_role
        })

    except Exception as e:
        db.rollback()
        logger.error(f"Error changing company role: {e}")
        return jsonify({'success': False, 'error': f'Błąd: {str(e)}'}), 500
    finally:
        db.close()


# ============================================================
# USER-COMPANY ASSOCIATIONS (Multi-company support)
# ============================================================

@bp.route('/users-api/<int:user_id>/companies', methods=['GET'])
@login_required
@role_required(SystemRole.ADMIN)
def admin_user_companies_list(user_id):
    """List all companies associated with a user."""
    db = SessionLocal()
    try:
        user = db.query(User).get(user_id)
        if not user:
            return jsonify({'success': False, 'error': 'Użytkownik nie znaleziony'}), 404

        associations = db.query(UserCompany).filter_by(user_id=user_id).all()
        result = []
        for uc in associations:
            company = db.query(Company).get(uc.company_id)
            result.append({
                'id': uc.id,
                'company_id': uc.company_id,
                'company_name': company.name if company else '(usunięta)',
                'role': uc.role,
                'is_primary': uc.is_primary,
                'created_at': uc.created_at.isoformat() if uc.created_at else None,
            })

        return jsonify({'success': True, 'companies': result})
    finally:
        db.close()


@bp.route('/users-api/<int:user_id>/companies', methods=['POST'])
@login_required
@role_required(SystemRole.ADMIN)
def admin_user_company_add(user_id):
    """Add a company association to a user."""
    db = SessionLocal()
    try:
        user = db.query(User).get(user_id)
        if not user:
            return jsonify({'success': False, 'error': 'Użytkownik nie znaleziony'}), 404

        data = request.get_json()
        company_id = data.get('company_id')
        role = data.get('role', 'MANAGER')

        if not company_id:
            return jsonify({'success': False, 'error': 'Brak company_id'}), 400

        company = db.query(Company).get(company_id)
        if not company:
            return jsonify({'success': False, 'error': 'Firma nie znaleziona'}), 404

        # Check if already associated
        existing = db.query(UserCompany).filter_by(
            user_id=user_id, company_id=company_id
        ).first()
        if existing:
            return jsonify({'success': False, 'error': 'Użytkownik jest już powiązany z tą firmą'}), 409

        # If user has no companies yet, make this the primary
        has_companies = db.query(UserCompany).filter_by(user_id=user_id).first()
        is_primary = not has_companies

        uc = UserCompany(
            user_id=user_id,
            company_id=company_id,
            role=role,
            is_primary=is_primary,
        )
        db.add(uc)
        db.commit()

        logger.info(f"Admin {current_user.email} added company {company_id} ({company.name}) to user {user.email} with role {role}")

        return jsonify({
            'success': True,
            'message': f'Firma {company.name} przypisana do użytkownika',
            'association_id': uc.id,
            'is_primary': is_primary,
        })
    except Exception as e:
        db.rollback()
        logger.error(f"Error adding company to user: {e}")
        return jsonify({'success': False, 'error': str(e)}), 500
    finally:
        db.close()


@bp.route('/users-api/<int:user_id>/companies/<int:company_id>', methods=['DELETE'])
@login_required
@role_required(SystemRole.ADMIN)
def admin_user_company_remove(user_id, company_id):
    """Remove a company association from a user."""
    db = SessionLocal()
    try:
        uc = db.query(UserCompany).filter_by(
            user_id=user_id, company_id=company_id
        ).first()
        if not uc:
            return jsonify({'success': False, 'error': 'Powiązanie nie znalezione'}), 404

        company_name = ''
        company = db.query(Company).get(company_id)
        if company:
            company_name = company.name

        db.delete(uc)
        db.commit()

        logger.info(f"Admin {current_user.email} removed company {company_id} ({company_name}) from user {user_id}")

        return jsonify({
            'success': True,
            'message': f'Usunięto powiązanie z firmą {company_name}',
        })
    except Exception as e:
        db.rollback()
        logger.error(f"Error removing company from user: {e}")
        return jsonify({'success': False, 'error': str(e)}), 500
    finally:
        db.close()


@bp.route('/users-api/<int:user_id>/companies/<int:company_id>/primary', methods=['PUT'])
@login_required
@role_required(SystemRole.ADMIN)
def admin_user_company_set_primary(user_id, company_id):
    """Set a company as the user's primary company."""
    db = SessionLocal()
    try:
        uc = db.query(UserCompany).filter_by(
            user_id=user_id, company_id=company_id
        ).first()
        if not uc:
            return jsonify({'success': False, 'error': 'Powiązanie nie znalezione'}), 404

        uc.is_primary = True
        uc.updated_at = datetime.now()
        # Trigger will handle clearing other primaries and syncing users.company_id
        db.commit()

        company = db.query(Company).get(company_id)
        logger.info(f"Admin {current_user.email} set company {company_id} as primary for user {user_id}")

        return jsonify({
            'success': True,
            'message': f'Firma {company.name if company else company_id} ustawiona jako główna',
        })
    except Exception as e:
        db.rollback()
        logger.error(f"Error setting primary company: {e}")
        return jsonify({'success': False, 'error': str(e)}), 500
    finally:
        db.close()
