"""
Authentication Views - Structured as: Groups, Users, Accounts, Subscriptions, Site User Access
Unified API Standard v1.0 compliant
"""
from rest_framework import viewsets, status, permissions, filters
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.views import APIView
from django.contrib.auth import authenticate
from django.utils import timezone
from django.db import transaction
from django_filters.rest_framework import DjangoFilterBackend
from drf_spectacular.utils import extend_schema, extend_schema_view
from igny8_core.api.base import AccountModelViewSet
from igny8_core.api.authentication import JWTAuthentication, CSRFExemptSessionAuthentication
from igny8_core.api.response import success_response, error_response
from igny8_core.api.throttles import DebugScopedRateThrottle
from igny8_core.api.pagination import CustomPageNumberPagination
from igny8_core.api.permissions import IsAuthenticatedAndActive, HasTenantAccess
from .models import User, Account, Plan, Subscription, Site, Sector, SiteUserAccess, Industry, IndustrySector, SeedKeyword
from .serializers import (
    UserSerializer, AccountSerializer, PlanSerializer, SubscriptionSerializer,
    RegisterSerializer, LoginSerializer, ChangePasswordSerializer,
    SiteSerializer, SectorSerializer, SiteUserAccessSerializer,
    IndustrySerializer, IndustrySectorSerializer, SeedKeywordSerializer,
    RefreshTokenSerializer, RequestPasswordResetSerializer, ResetPasswordSerializer
)
from .permissions import IsOwnerOrAdmin, IsEditorOrAbove
from .utils import generate_access_token, generate_refresh_token, get_token_expiry, decode_token
from .models import PasswordResetToken
import jwt


# ============================================================================
# 1. GROUPS - Define user roles and permissions across the system
# ============================================================================

@extend_schema_view(
    list=extend_schema(tags=['Authentication']),
    retrieve=extend_schema(tags=['Authentication']),
)
class GroupsViewSet(viewsets.ViewSet):
    """
    ViewSet for managing user roles and permissions (Groups).
    Groups are defined by the User.ROLE_CHOICES.
    Unified API Standard v1.0 compliant
    """
    permission_classes = [IsOwnerOrAdmin]
    throttle_scope = 'auth'
    throttle_classes = [DebugScopedRateThrottle]
    
    def list(self, request):
        """List all available roles/groups."""
        roles = [
            {
                'id': 'developer',
                'name': 'Developer / Super Admin',
                'description': 'Full access across all accounts (bypasses all filters)',
                'permissions': ['full_access', 'bypass_filters', 'all_modules']
            },
            {
                'id': 'owner',
                'name': 'Owner',
                'description': 'Full account access, billing, automation',
                'permissions': ['account_management', 'billing', 'automation', 'all_sites']
            },
            {
                'id': 'admin',
                'name': 'Admin',
                'description': 'Manage content modules, view billing (no edit)',
                'permissions': ['content_management', 'view_billing', 'all_sites']
            },
            {
                'id': 'editor',
                'name': 'Editor',
                'description': 'Generate AI content, manage clusters/tasks',
                'permissions': ['ai_content', 'manage_clusters', 'manage_tasks', 'assigned_sites']
            },
            {
                'id': 'viewer',
                'name': 'Viewer',
                'description': 'Read-only dashboards',
                'permissions': ['read_only', 'assigned_sites']
            },
            {
                'id': 'system_bot',
                'name': 'System Bot',
                'description': 'System automation user',
                'permissions': ['automation_only']
            }
        ]
        return success_response(data={'groups': roles}, request=request)
    
    @action(detail=False, methods=['get'], url_path='permissions')
    def permissions(self, request):
        """Get permissions for a specific role."""
        role = request.query_params.get('role')
        if not role:
            return error_response(
                error='role parameter is required',
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
        
        role_permissions = {
            'developer': ['full_access', 'bypass_filters', 'all_modules', 'all_accounts'],
            'owner': ['account_management', 'billing', 'automation', 'all_sites', 'user_management'],
            'admin': ['content_management', 'view_billing', 'all_sites', 'user_management'],
            'editor': ['ai_content', 'manage_clusters', 'manage_tasks', 'assigned_sites'],
            'viewer': ['read_only', 'assigned_sites'],
            'system_bot': ['automation_only']
        }
        
        permissions_list = role_permissions.get(role, [])
        return success_response(
            data={
                'role': role,
                'permissions': permissions_list
            },
            request=request
        )


# ============================================================================
# 2. USERS - Manage global user records and credentials
# ============================================================================

@extend_schema_view(
    list=extend_schema(tags=['Authentication']),
    create=extend_schema(tags=['Authentication']),
    retrieve=extend_schema(tags=['Authentication']),
    update=extend_schema(tags=['Authentication']),
    partial_update=extend_schema(tags=['Authentication']),
    destroy=extend_schema(tags=['Authentication']),
)
class UsersViewSet(AccountModelViewSet):
    """
    ViewSet for managing global user records and credentials.
    Users are global, but belong to accounts.
    Unified API Standard v1.0 compliant
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [IsAuthenticatedAndActive, HasTenantAccess, IsOwnerOrAdmin]
    pagination_class = CustomPageNumberPagination
    throttle_scope = 'auth'
    throttle_classes = [DebugScopedRateThrottle]
    
    def get_queryset(self):
        """Return users based on access level."""
        user = self.request.user
        if not user or not user.is_authenticated:
            return User.objects.none()
        
        # Developers can see all users
        if user.is_developer():
            return User.objects.all()
        
        # Owners/Admins can see users in their account
        if user.role in ['owner', 'admin'] and user.account:
            return User.objects.filter(account=user.account)
        
        # Others can only see themselves
        return User.objects.filter(id=user.id)
    
    @action(detail=False, methods=['post'])
    def create_user(self, request):
        """Create a new user (separate from registration)."""
        from django.contrib.auth.password_validation import validate_password
        
        email = request.data.get('email')
        username = request.data.get('username')
        password = request.data.get('password')
        role = request.data.get('role', 'viewer')
        account_id = request.data.get('account_id')
        
        if not email or not username or not password:
            return error_response(
                error='email, username, and password are required',
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
        
        # Validate password
        try:
            validate_password(password)
        except Exception as e:
            return error_response(
                error=str(e),
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
        
        # Get account
        account = None
        if account_id:
            try:
                account = Account.objects.get(id=account_id)
            except Account.DoesNotExist:
                return error_response(
                    error=f'Account with id {account_id} does not exist',
                    status_code=status.HTTP_400_BAD_REQUEST,
                    request=request
                )
        else:
            # Use current user's account
            if request.user.account:
                account = request.user.account
        
        # Create user
        try:
            user = User.objects.create_user(
                username=username,
                email=email,
                password=password,
                role=role,
                account=account
            )
            serializer = UserSerializer(user)
            return success_response(
                data={'user': serializer.data},
                status_code=status.HTTP_201_CREATED,
                request=request
            )
        except Exception as e:
            return error_response(
                error=str(e),
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
    
    @action(detail=True, methods=['post'])
    def update_role(self, request, pk=None):
        """Update user role."""
        user = self.get_object()
        new_role = request.data.get('role')
        
        if not new_role:
            return error_response(
                error='role is required',
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
        
        if new_role not in [choice[0] for choice in User.ROLE_CHOICES]:
            return error_response(
                error=f'Invalid role. Must be one of: {[c[0] for c in User.ROLE_CHOICES]}',
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
        
        user.role = new_role
        user.save()
        
        serializer = UserSerializer(user)
        return success_response(data={'user': serializer.data}, request=request)


# ============================================================================
# 3. ACCOUNTS - Register each unique organization/user space
# ============================================================================

@extend_schema_view(
    list=extend_schema(tags=['Authentication']),
    create=extend_schema(tags=['Authentication']),
    retrieve=extend_schema(tags=['Authentication']),
    update=extend_schema(tags=['Authentication']),
    partial_update=extend_schema(tags=['Authentication']),
    destroy=extend_schema(tags=['Authentication']),
)
class AccountsViewSet(AccountModelViewSet):
    """
    ViewSet for managing accounts (unique organization/user spaces).
    Unified API Standard v1.0 compliant
    """
    queryset = Account.objects.all()
    serializer_class = AccountSerializer
    permission_classes = [IsAuthenticatedAndActive, HasTenantAccess, IsOwnerOrAdmin]
    pagination_class = CustomPageNumberPagination
    throttle_scope = 'auth'
    throttle_classes = [DebugScopedRateThrottle]
    
    def get_queryset(self):
        """Return accounts based on access level."""
        user = self.request.user
        if not user or not user.is_authenticated:
            return Account.objects.none()
        
        # Developers can see all accounts
        if user.is_developer():
            return Account.objects.all()
        
        # Owners can see their own accounts
        if user.role == 'owner':
            return Account.objects.filter(owner=user)
        
        # Admins can see their account
        if user.role == 'admin' and user.account:
            return Account.objects.filter(id=user.account.id)
        
        return Account.objects.none()
    
    def perform_create(self, serializer):
        """Create account with owner."""
        user = self.request.user
        
        # plan_id is mapped to plan in serializer (source='plan')
        plan = serializer.validated_data.get('plan')
        
        if not plan:
            from rest_framework.exceptions import ValidationError
            raise ValidationError("plan_id is required")
        
        # Set owner to current user if not provided
        owner = serializer.validated_data.get('owner')
        if not owner:
            owner = user
        
        account = serializer.save(plan=plan, owner=owner)
        return account



# ============================================================================
# 4. SUBSCRIPTIONS - Control plan level, limits, and billing per account
# ============================================================================

@extend_schema_view(
    list=extend_schema(tags=['Authentication']),
    create=extend_schema(tags=['Authentication']),
    retrieve=extend_schema(tags=['Authentication']),
    update=extend_schema(tags=['Authentication']),
    partial_update=extend_schema(tags=['Authentication']),
    destroy=extend_schema(tags=['Authentication']),
)
class SubscriptionsViewSet(AccountModelViewSet):
    """
    ViewSet for managing subscriptions (plan level, limits, billing per account).
    Unified API Standard v1.0 compliant
    """
    queryset = Subscription.objects.all()
    permission_classes = [IsAuthenticatedAndActive, HasTenantAccess, IsOwnerOrAdmin]
    pagination_class = CustomPageNumberPagination
    # Use relaxed auth throttle to avoid 429s during onboarding plan fetches
    throttle_scope = 'auth_read'
    throttle_classes = [DebugScopedRateThrottle]
    
    def get_queryset(self):
        """Return subscriptions based on access level."""
        user = self.request.user
        if not user or not user.is_authenticated:
            return Subscription.objects.none()
        
        # Developers can see all subscriptions
        if user.is_developer():
            return Subscription.objects.all()
        
        # Owners/Admins can see subscriptions for their account
        if user.role in ['owner', 'admin'] and user.account:
            return Subscription.objects.filter(account=user.account)
        
        return Subscription.objects.none()
    
    def get_serializer_class(self):
        """Return appropriate serializer."""
        return SubscriptionSerializer
    
    @action(detail=False, methods=['get'], url_path='by-account/(?P<account_id>[^/.]+)')
    def by_account(self, request, account_id=None):
        """Get subscription for a specific account."""
        try:
            subscription = Subscription.objects.get(account_id=account_id)
            serializer = self.get_serializer(subscription)
            return success_response(
                data={'subscription': serializer.data},
                request=request
            )
        except Subscription.DoesNotExist:
            return error_response(
                error='Subscription not found for this account',
                status_code=status.HTTP_404_NOT_FOUND,
                request=request
            )


# ============================================================================
# 5. SITE USER ACCESS - Assign users access to specific sites within account
# ============================================================================

@extend_schema_view(
    list=extend_schema(tags=['Authentication']),
    create=extend_schema(tags=['Authentication']),
    retrieve=extend_schema(tags=['Authentication']),
    update=extend_schema(tags=['Authentication']),
    partial_update=extend_schema(tags=['Authentication']),
    destroy=extend_schema(tags=['Authentication']),
)
class SiteUserAccessViewSet(AccountModelViewSet):
    """
    ViewSet for managing Site-User access permissions.
    Assign users access to specific sites within their account.
    Unified API Standard v1.0 compliant
    """
    serializer_class = SiteUserAccessSerializer
    permission_classes = [IsAuthenticatedAndActive, HasTenantAccess, IsOwnerOrAdmin]
    pagination_class = CustomPageNumberPagination
    throttle_scope = 'auth'
    throttle_classes = [DebugScopedRateThrottle]
    
    def get_queryset(self):
        """Return access records for sites in user's account."""
        user = self.request.user
        if not user or not user.is_authenticated:
            return SiteUserAccess.objects.none()
        
        # Developers can see all access records
        if user.is_developer():
            return SiteUserAccess.objects.all()
        
        if not user.account:
            return SiteUserAccess.objects.none()
        
        # Return access records for sites in user's account
        return SiteUserAccess.objects.filter(site__account=user.account)
    
    def perform_create(self, serializer):
        """Create site user access with granted_by."""
        user = self.request.user
        serializer.save(granted_by=user)


# ============================================================================
# SUPPORTING VIEWSETS (Sites, Sectors, Industries, Plans, Auth)
# ============================================================================

@extend_schema_view(
    list=extend_schema(tags=['Authentication']),
    retrieve=extend_schema(tags=['Authentication']),
)
class PlanViewSet(viewsets.ReadOnlyModelViewSet):
    """
    ViewSet for listing active subscription plans.
    Excludes internal-only plans (Free/Internal) from public listings.
    Unified API Standard v1.0 compliant
    """
    queryset = Plan.objects.filter(is_active=True, is_internal=False)
    serializer_class = PlanSerializer
    permission_classes = [permissions.AllowAny]
    pagination_class = CustomPageNumberPagination
    # Plans are public and should not throttle aggressively to avoid blocking signup/onboarding
    throttle_scope = None
    throttle_classes: list = []
    
    def list(self, request, *args, **kwargs):
        """Override list to return paginated response with unified format"""
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        serializer = self.get_serializer(queryset, many=True)
        return success_response(data={'results': serializer.data}, request=request)
    
    def retrieve(self, request, *args, **kwargs):
        """Override retrieve to return unified format"""
        try:
            instance = self.get_object()
            serializer = self.get_serializer(instance)
            return success_response(data=serializer.data, request=request)
        except Exception as e:
            return error_response(
                error=str(e),
                status_code=status.HTTP_404_NOT_FOUND,
                request=request
            )


@extend_schema_view(
    list=extend_schema(tags=['Authentication']),
    create=extend_schema(tags=['Authentication']),
    retrieve=extend_schema(tags=['Authentication']),
    update=extend_schema(tags=['Authentication']),
    partial_update=extend_schema(tags=['Authentication']),
    destroy=extend_schema(tags=['Authentication']),
)
class SiteViewSet(AccountModelViewSet):
    """ViewSet for managing Sites."""
    serializer_class = SiteSerializer
    permission_classes = [IsAuthenticatedAndActive, HasTenantAccess, IsEditorOrAbove]
    authentication_classes = [JWTAuthentication]
    
    def get_permissions(self):
        """Allow normal users (viewer) to create sites, but require editor+ for other operations."""
        # Allow public read access for list requests with slug filter (used by Sites Renderer)
        if self.action == 'list' and self.request.query_params.get('slug'):
            from rest_framework.permissions import AllowAny
            return [AllowAny()]
        if self.action == 'create':
            # For create, only require authentication - not active account status
            return [permissions.IsAuthenticated()]
        return [IsAuthenticatedAndActive(), HasTenantAccess(), IsEditorOrAbove()]
    
    def get_queryset(self):
        """Return sites accessible to the current user."""
        # If this is a public request (no auth) with slug filter, return site by slug
        if not self.request.user or not self.request.user.is_authenticated:
            slug = self.request.query_params.get('slug')
            if slug:
                # Return queryset directly from model (bypassing base class account filtering)
                return Site.objects.filter(slug=slug, is_active=True)
            return Site.objects.none()
        
        user = self.request.user
        
        account = getattr(user, 'account', None)
        if not account:
            return Site.objects.none()
        
        if hasattr(user, 'get_accessible_sites'):
            return user.get_accessible_sites()
        
        return Site.objects.filter(account=account)
    
    def perform_create(self, serializer):
        """Create site with account and auto-grant access to creator."""
        account = getattr(self.request, 'account', None)
        if not account:
            user = self.request.user
            if user and user.is_authenticated:
                account = getattr(user, 'account', None)
        
        # Check hard limit for sites
        from igny8_core.business.billing.services.limit_service import LimitService, HardLimitExceededError
        try:
            LimitService.check_hard_limit(account, 'sites', additional_count=1)
        except HardLimitExceededError as e:
            from rest_framework.exceptions import PermissionDenied
            raise PermissionDenied(str(e))
        
        # Multiple sites can be active simultaneously - no constraint
        site = serializer.save(account=account)
        
        # Auto-create SiteUserAccess for owner/admin who creates the site
        user = self.request.user
        if user and user.is_authenticated and hasattr(user, 'role'):
            if user.role in ['owner', 'admin']:
                from igny8_core.auth.models import SiteUserAccess
                SiteUserAccess.objects.get_or_create(
                    user=user,
                    site=site,
                    defaults={'granted_by': user}
                )
    
    def perform_update(self, serializer):
        """Update site."""
        account = getattr(self.request, 'account', None)
        if not account:
            account = getattr(serializer.instance, 'account', None)
        
        # Multiple sites can be active simultaneously - no constraint
        serializer.save()
    
    @action(detail=True, methods=['get'])
    def sectors(self, request, pk=None):
        """Get all sectors for this site."""
        site = self.get_object()
        sectors = site.sectors.filter(is_active=True)
        serializer = SectorSerializer(sectors, many=True)
        return success_response(
            data=serializer.data,
            request=request
        )
    
    @action(detail=True, methods=['post'], url_path='set_active')
    def set_active(self, request, pk=None):
        """Set this site as active (multiple sites can be active simultaneously)."""
        site = self.get_object()
        
        # Simply activate this site - no need to deactivate others
        site.is_active = True
        site.status = 'active'
        site.save()
        
        serializer = self.get_serializer(site)
        return success_response(
            data={'site': serializer.data},
            message=f'Site "{site.name}" is now active',
            request=request
        )
    
    @action(detail=True, methods=['post'], url_path='select_sectors')
    def select_sectors(self, request, pk=None):
        """Select industry and sectors for this site."""
        import logging
        logger = logging.getLogger(__name__)
        
        try:
            site = self.get_object()
        except Exception as e:
            logger.error(f"Error getting site object: {str(e)}", exc_info=True)
            return error_response(
                error=f'Site not found: {str(e)}',
                status_code=status.HTTP_404_NOT_FOUND,
                request=request
            )
        
        sector_slugs = request.data.get('sector_slugs', [])
        industry_slug = request.data.get('industry_slug')
        
        if not industry_slug:
            return error_response(
                error='Industry slug is required',
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
        
        try:
            industry = Industry.objects.get(slug=industry_slug, is_active=True)
        except Industry.DoesNotExist:
            return error_response(
                error=f'Industry with slug "{industry_slug}" not found',
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
        
        site.industry = industry
        site.save()
        
        if not sector_slugs:
            return success_response(
                data={
                    'site': SiteSerializer(site).data,
                    'sectors': []
                },
                message=f'Industry "{industry.name}" set for site. No sectors selected.',
                request=request
            )
        
        # Get plan's max_industries limit (if set), otherwise default to 5
        max_sectors = site.get_max_sectors_limit()
        
        if len(sector_slugs) > max_sectors:
            return error_response(
                error=f'Maximum {max_sectors} sectors allowed per site for this plan',
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
        
        created_sectors = []
        updated_sectors = []
        
        existing_sector_slugs = set(sector_slugs)
        site.sectors.exclude(slug__in=existing_sector_slugs).update(is_active=False)
        
        industry_sectors_map = {}
        for sector_slug in sector_slugs:
            industry_sector = IndustrySector.objects.filter(
                industry=industry,
                slug=sector_slug,
                is_active=True
            ).first()
            
            if not industry_sector:
                return error_response(
                    error=f'Sector "{sector_slug}" not found in industry "{industry.name}"',
                    status_code=status.HTTP_400_BAD_REQUEST,
                    request=request
                )
            
            industry_sectors_map[sector_slug] = industry_sector
        
        for sector_slug, industry_sector in industry_sectors_map.items():
            try:
                # Check if site has account before proceeding
                if not site.account:
                    logger.error(f"Site {site.id} has no account assigned")
                    return error_response(
                        error=f'Site "{site.name}" has no account assigned. Please contact support.',
                        status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                        request=request
                    )
                
                # Create or get sector - account will be set automatically in save() method
                # But we need to pass it in defaults for get_or_create to work
                sector, created = Sector.objects.get_or_create(
                    site=site,
                    slug=sector_slug,
                    defaults={
                        'industry_sector': industry_sector,
                        'name': industry_sector.name,
                        'description': industry_sector.description or '',
                        'is_active': True,
                        'status': 'active',
                        'account': site.account  # Pass the account object, not the ID
                    }
                )
                
                if not created:
                    # Update existing sector
                    sector.industry_sector = industry_sector
                    sector.name = industry_sector.name
                    sector.description = industry_sector.description or ''
                    sector.is_active = True
                    sector.status = 'active'
                    # Ensure account is set (save() will also set it, but be explicit)
                    if not sector.account:
                        sector.account = site.account
                    sector.save()
                    updated_sectors.append(sector)
                else:
                    created_sectors.append(sector)
            except Exception as e:
                logger.error(f"Error creating/updating sector {sector_slug}: {str(e)}", exc_info=True)
                return error_response(
                    error=f'Failed to create/update sector "{sector_slug}": {str(e)}',
                    status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                    request=request
                )
        
        # Get plan's max_industries limit (if set), otherwise default to 5
        max_sectors = site.get_max_sectors_limit()
        
        if site.get_active_sectors_count() > max_sectors:
            return error_response(
                error=f'Maximum {max_sectors} sectors allowed per site for this plan',
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
        
        serializer = SectorSerializer(site.sectors.filter(is_active=True), many=True)
        return success_response(
            data={
                'created_count': len(created_sectors),
                'updated_count': len(updated_sectors),
                'sectors': serializer.data,
                'site': SiteSerializer(site).data
            },
            message=f'Selected {len(sector_slugs)} sectors from industry "{industry.name}".',
            request=request
        )


@extend_schema_view(
    list=extend_schema(tags=['Authentication']),
    create=extend_schema(tags=['Authentication']),
    retrieve=extend_schema(tags=['Authentication']),
    update=extend_schema(tags=['Authentication']),
    partial_update=extend_schema(tags=['Authentication']),
    destroy=extend_schema(tags=['Authentication']),
)
class SectorViewSet(AccountModelViewSet):
    """ViewSet for managing Sectors."""
    serializer_class = SectorSerializer
    permission_classes = [IsAuthenticatedAndActive, HasTenantAccess, IsEditorOrAbove]
    authentication_classes = [JWTAuthentication]
    
    def get_queryset(self):
        """Return sectors from sites accessible to the current user."""
        user = self.request.user
        if not user or not user.is_authenticated:
            return Sector.objects.none()
        accessible_sites = user.get_accessible_sites()
        return Sector.objects.filter(site__in=accessible_sites)
    
    def get_queryset_with_site_filter(self):
        """Get queryset, optionally filtered by site_id."""
        queryset = self.get_queryset()
        site_id = self.request.query_params.get('site_id')
        if site_id:
            queryset = queryset.filter(site_id=site_id)
        return queryset
    
    def list(self, request, *args, **kwargs):
        """Override list to apply site filter."""
        queryset = self.get_queryset_with_site_filter()
        serializer = self.get_serializer(queryset, many=True)
        return success_response(
            data=serializer.data,
            request=request
        )


@extend_schema_view(
    list=extend_schema(tags=['Authentication']),
    retrieve=extend_schema(tags=['Authentication']),
)
class IndustryViewSet(viewsets.ReadOnlyModelViewSet):
    """
    ViewSet for industry templates.
    Unified API Standard v1.0 compliant
    """
    queryset = Industry.objects.filter(is_active=True).prefetch_related('sectors')
    serializer_class = IndustrySerializer
    permission_classes = [permissions.AllowAny]
    pagination_class = CustomPageNumberPagination
    throttle_scope = 'auth'
    throttle_classes = [DebugScopedRateThrottle]
    
    def list(self, request):
        """Get all industries with their sectors."""
        industries = self.get_queryset()
        serializer = self.get_serializer(industries, many=True)
        return success_response(
            data={'industries': serializer.data},
            request=request
        )
    
    def retrieve(self, request, *args, **kwargs):
        """Override retrieve to return unified format"""
        try:
            instance = self.get_object()
            serializer = self.get_serializer(instance)
            return success_response(data=serializer.data, request=request)
        except Exception as e:
            return error_response(
                error=str(e),
                status_code=status.HTTP_404_NOT_FOUND,
                request=request
            )


@extend_schema_view(
    list=extend_schema(tags=['Authentication']),
    retrieve=extend_schema(tags=['Authentication']),
)
class SeedKeywordViewSet(viewsets.ReadOnlyModelViewSet):
    """
    ViewSet for SeedKeyword - Global reference data (read-only for non-admins).
    Unified API Standard v1.0 compliant
    """
    queryset = SeedKeyword.objects.filter(is_active=True).select_related('industry', 'sector')
    serializer_class = SeedKeywordSerializer
    permission_classes = [permissions.AllowAny]  # Read-only, allow any authenticated user
    pagination_class = CustomPageNumberPagination
    throttle_scope = 'auth'
    throttle_classes = [DebugScopedRateThrottle]
    
    filter_backends = [filters.SearchFilter, filters.OrderingFilter, DjangoFilterBackend]
    search_fields = ['keyword']
    ordering_fields = ['keyword', 'volume', 'difficulty', 'created_at']
    ordering = ['keyword']
    filterset_fields = ['industry', 'sector', 'country', 'is_active']
    
    def retrieve(self, request, *args, **kwargs):
        """Override retrieve to return unified format"""
        try:
            instance = self.get_object()
            serializer = self.get_serializer(instance)
            return success_response(data=serializer.data, request=request)
        except Exception as e:
            return error_response(
                error=str(e),
                status_code=status.HTTP_404_NOT_FOUND,
                request=request
            )
    
    def get_queryset(self):
        """Filter by industry and sector if provided."""
        queryset = super().get_queryset()
        industry_id = self.request.query_params.get('industry_id')
        industry_name = self.request.query_params.get('industry_name')
        sector_id = self.request.query_params.get('sector_id')
        sector_name = self.request.query_params.get('sector_name')
        
        if industry_id:
            queryset = queryset.filter(industry_id=industry_id)
        if industry_name:
            queryset = queryset.filter(industry__name__icontains=industry_name)
        if sector_id:
            queryset = queryset.filter(sector_id=sector_id)
        if sector_name:
            queryset = queryset.filter(sector__name__icontains=sector_name)
        
        return queryset
    
    @action(detail=False, methods=['post'], url_path='import_seed_keywords', url_name='import_seed_keywords')
    def import_seed_keywords(self, request):
        """
        Import seed keywords from CSV (Admin/Superuser only).
        Expected columns: keyword, industry_name, sector_name, volume, difficulty, country
        """
        import csv
        from django.db import transaction
        
        # Check admin/superuser permission
        if not (request.user.is_staff or request.user.is_superuser):
            return error_response(
                error='Admin or superuser access required',
                status_code=status.HTTP_403_FORBIDDEN,
                request=request
            )
        
        if 'file' not in request.FILES:
            return error_response(
                error='No file provided',
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
        
        file = request.FILES['file']
        if not file.name.endswith('.csv'):
            return error_response(
                error='File must be a CSV',
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
        
        try:
            # Parse CSV
            decoded_file = file.read().decode('utf-8')
            csv_reader = csv.DictReader(decoded_file.splitlines())
            
            imported_count = 0
            skipped_count = 0
            errors = []
            
            with transaction.atomic():
                for row_num, row in enumerate(csv_reader, start=2):  # Start at 2 (header is row 1)
                    try:
                        keyword_text = row.get('keyword', '').strip()
                        industry_name = row.get('industry_name', '').strip()
                        sector_name = row.get('sector_name', '').strip()
                        
                        if not all([keyword_text, industry_name, sector_name]):
                            skipped_count += 1
                            continue
                        
                        # Get or create industry
                        industry = Industry.objects.filter(name=industry_name).first()
                        if not industry:
                            errors.append(f"Row {row_num}: Industry '{industry_name}' not found")
                            skipped_count += 1
                            continue
                        
                        # Get or create industry sector
                        sector = IndustrySector.objects.filter(
                            industry=industry,
                            name=sector_name
                        ).first()
                        if not sector:
                            errors.append(f"Row {row_num}: Sector '{sector_name}' not found for industry '{industry_name}'")
                            skipped_count += 1
                            continue
                        
                        # Check if keyword already exists
                        existing = SeedKeyword.objects.filter(
                            keyword=keyword_text,
                            industry=industry,
                            sector=sector
                        ).first()
                        
                        if existing:
                            skipped_count += 1
                            continue
                        
                        # Create seed keyword
                        SeedKeyword.objects.create(
                            keyword=keyword_text,
                            industry=industry,
                            sector=sector,
                            volume=int(row.get('volume', 0) or 0),
                            difficulty=int(row.get('difficulty', 0) or 0),
                            country=row.get('country', 'US') or 'US',
                            is_active=True
                        )
                        imported_count += 1
                        
                    except Exception as e:
                        errors.append(f"Row {row_num}: {str(e)}")
                        skipped_count += 1
            
            return success_response(
                data={
                    'imported': imported_count,
                    'skipped': skipped_count,
                    'errors': errors[:10] if errors else []  # Limit errors to first 10
                },
                message=f'Import completed: {imported_count} keywords imported, {skipped_count} skipped',
                request=request
            )
            
        except Exception as e:
            return error_response(
                error=f'Failed to import keywords: {str(e)}',
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                request=request
            )


# ============================================================================
# AUTHENTICATION ENDPOINTS (Register, Login, Change Password, Me)
# ============================================================================

@extend_schema_view(
    register=extend_schema(tags=['Authentication']),
    login=extend_schema(tags=['Authentication']),
    change_password=extend_schema(tags=['Authentication']),
    refresh_token=extend_schema(tags=['Authentication']),
)
class AuthViewSet(viewsets.GenericViewSet):
    """Authentication endpoints.
    Unified API Standard v1.0 compliant
    """
    permission_classes = [permissions.AllowAny]
    throttle_scope = 'auth_strict'
    throttle_classes = [DebugScopedRateThrottle]
    
    @action(detail=False, methods=['post'])
    def register(self, request):
        """User registration endpoint."""
        serializer = RegisterSerializer(data=request.data)
        if serializer.is_valid():
            user = serializer.save()
            
            # Log the user in (create session for session authentication)
            from django.contrib.auth import login
            login(request, user)
            
            # Get account from user
            account = getattr(user, 'account', None)
            
            # Generate JWT tokens
            access_token = generate_access_token(user, account)
            refresh_token = generate_refresh_token(user, account)
            access_expires_at = get_token_expiry('access')
            refresh_expires_at = get_token_expiry('refresh')
            
            user_serializer = UserSerializer(user)
            return success_response(
                data={
                    'user': user_serializer.data,
                    'tokens': {
                        'access': access_token,
                        'refresh': refresh_token,
                        'access_expires_at': access_expires_at.isoformat(),
                        'refresh_expires_at': refresh_expires_at.isoformat(),
                    }
                },
                message='Registration successful',
                status_code=status.HTTP_201_CREATED,
                request=request
            )
        return error_response(
            error='Validation failed',
            errors=serializer.errors,
            status_code=status.HTTP_400_BAD_REQUEST,
            request=request
        )
    
    @action(detail=False, methods=['post'])
    def login(self, request):
        """User login endpoint."""
        serializer = LoginSerializer(data=request.data)
        if serializer.is_valid():
            email = serializer.validated_data['email']
            password = serializer.validated_data['password']
            
            try:
                user = User.objects.select_related('account', 'account__plan').get(email=email)
            except User.DoesNotExist:
                return error_response(
                    error='Invalid credentials',
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    request=request
                )
            
            if user.check_password(password):
                # Ensure user has an account
                account = getattr(user, 'account', None)
                if account is None:
                    return error_response(
                        error='Account not configured for this user. Please contact support.',
                        status_code=status.HTTP_403_FORBIDDEN,
                        request=request,
                    )
                
                # Ensure account has an active plan
                plan = getattr(account, 'plan', None)
                if plan is None or getattr(plan, 'is_active', False) is False:
                    return error_response(
                        error='Active subscription required. Visit igny8.com/pricing to subscribe.',
                        status_code=status.HTTP_402_PAYMENT_REQUIRED,
                        request=request,
                    )
                
                # Log the user in (create session for session authentication)
                from django.contrib.auth import login
                login(request, user)
                
                # Generate JWT tokens
                access_token = generate_access_token(user, account)
                refresh_token = generate_refresh_token(user, account)
                access_expires_at = get_token_expiry('access')
                refresh_expires_at = get_token_expiry('refresh')
                
                user_serializer = UserSerializer(user)
                return success_response(
                    data={
                        'user': user_serializer.data,
                        'access': access_token,
                        'refresh': refresh_token,
                        'access_expires_at': access_expires_at.isoformat(),
                        'refresh_expires_at': refresh_expires_at.isoformat(),
                    },
                    message='Login successful',
                    request=request
                )
            
            return error_response(
                error='Invalid credentials',
                status_code=status.HTTP_401_UNAUTHORIZED,
                request=request
            )
        
        return error_response(
            error='Validation failed',
            errors=serializer.errors,
            status_code=status.HTTP_400_BAD_REQUEST,
            request=request
        )
    
    @action(detail=False, methods=['post'], permission_classes=[permissions.IsAuthenticated])
    def change_password(self, request):
        """Change password endpoint."""
        serializer = ChangePasswordSerializer(data=request.data, context={'request': request})
        if serializer.is_valid():
            user = request.user
            if not user.check_password(serializer.validated_data['old_password']):
                return error_response(
                    error='Current password is incorrect',
                    status_code=status.HTTP_400_BAD_REQUEST,
                    request=request
                )
            
            user.set_password(serializer.validated_data['new_password'])
            user.save()
            
            return success_response(
                message='Password changed successfully',
                request=request
            )
        
        return error_response(
            error='Validation failed',
            errors=serializer.errors,
            status_code=status.HTTP_400_BAD_REQUEST,
            request=request
        )
    
    @action(detail=False, methods=['get'], permission_classes=[permissions.IsAuthenticated])
    def me(self, request):
        """Get current user information."""
        # Refresh user from DB to get latest account/plan data
        # This ensures account/plan changes are reflected immediately
        user = User.objects.select_related('account', 'account__plan').get(id=request.user.id)
        serializer = UserSerializer(user)
        return success_response(
            data={'user': serializer.data},
            request=request
        )
    
    @action(detail=False, methods=['post'], permission_classes=[permissions.AllowAny])
    def refresh(self, request):
        """Refresh access token using refresh token."""
        serializer = RefreshTokenSerializer(data=request.data)
        if not serializer.is_valid():
            return error_response(
                error='Validation failed',
                errors=serializer.errors,
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
        
        refresh_token = serializer.validated_data['refresh']
        
        try:
            # Decode and validate refresh token
            payload = decode_token(refresh_token)
            
            # Verify it's a refresh token
            if payload.get('type') != 'refresh':
                return error_response(
                    error='Invalid token type',
                    status_code=status.HTTP_400_BAD_REQUEST,
                    request=request
                )
            
            # Get user
            user_id = payload.get('user_id')
            account_id = payload.get('account_id')
            
            try:
                user = User.objects.get(id=user_id)
            except User.DoesNotExist:
                return error_response(
                    error='User not found',
                    status_code=status.HTTP_404_NOT_FOUND,
                    request=request
                )
            
            # Get account
            account_id = payload.get('account_id')
            account = None
            if account_id:
                try:
                    account = Account.objects.get(id=account_id)
                except Account.DoesNotExist:
                    pass
            
            if not account:
                account = getattr(user, 'account', None)
            
            # Generate new access token
            access_token = generate_access_token(user, account)
            access_expires_at = get_token_expiry('access')
            
            return success_response(
                data={
                    'access': access_token,
                    'access_expires_at': access_expires_at.isoformat()
                },
                request=request
            )
            
        except jwt.InvalidTokenError as e:
            return error_response(
                error='Invalid or expired refresh token',
                status_code=status.HTTP_401_UNAUTHORIZED,
                request=request
            )
    
    @action(detail=False, methods=['post'], permission_classes=[permissions.AllowAny])
    def request_reset(self, request):
        """Request password reset - sends email with reset token."""
        serializer = RequestPasswordResetSerializer(data=request.data)
        if not serializer.is_valid():
            return error_response(
                error='Validation failed',
                errors=serializer.errors,
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
        
        email = serializer.validated_data['email']
        
        try:
            user = User.objects.get(email=email)
        except User.DoesNotExist:
            # Don't reveal if email exists - return success anyway
            return success_response(
                message='If an account with that email exists, a password reset link has been sent.',
                request=request
            )
        
        # Generate secure token
        import secrets
        token = secrets.token_urlsafe(32)
        
        # Create reset token (expires in 1 hour)
        from django.utils import timezone
        from datetime import timedelta
        expires_at = timezone.now() + timedelta(hours=1)
        
        PasswordResetToken.objects.create(
            user=user,
            token=token,
            expires_at=expires_at
        )
        
        # Send email (async via Celery if available, otherwise sync)
        try:
            from igny8_core.modules.system.tasks import send_password_reset_email
            send_password_reset_email.delay(user.id, token)
        except:
            # Fallback to sync email sending
            from django.core.mail import send_mail
            from django.conf import settings
            
            reset_url = f"{request.scheme}://{request.get_host()}/reset-password?token={token}"
            
            send_mail(
                subject='Reset Your IGNY8 Password',
                message=f'Click the following link to reset your password: {reset_url}\n\nThis link expires in 1 hour.',
                from_email=getattr(settings, 'DEFAULT_FROM_EMAIL', 'noreply@igny8.com'),
                recipient_list=[user.email],
                fail_silently=False,
            )
        
        return success_response(
            message='If an account with that email exists, a password reset link has been sent.',
            request=request
        )
    
    @action(detail=False, methods=['post'], permission_classes=[permissions.AllowAny])
    def reset_password(self, request):
        """Reset password using reset token."""
        serializer = ResetPasswordSerializer(data=request.data)
        if not serializer.is_valid():
            return error_response(
                error='Validation failed',
                errors=serializer.errors,
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
        
        token = serializer.validated_data['token']
        new_password = serializer.validated_data['new_password']
        
        try:
            reset_token = PasswordResetToken.objects.get(token=token)
        except PasswordResetToken.DoesNotExist:
            return error_response(
                error='Invalid reset token',
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
        
        # Check if token is valid
        if not reset_token.is_valid():
            return error_response(
                error='Reset token has expired or has already been used',
                status_code=status.HTTP_400_BAD_REQUEST,
                request=request
            )
        
        # Update password
        user = reset_token.user
        user.set_password(new_password)
        user.save()
        
        # Mark token as used
        reset_token.used = True
        reset_token.save()
        
        return success_response(
            message='Password has been reset successfully',
            request=request
        )


# ============================================================================
# CSV Import/Export Views for Admin
# ============================================================================

from django.http import HttpResponse, JsonResponse
from django.contrib.admin.views.decorators import staff_member_required
from django.views.decorators.http import require_http_methods
import csv
import io


@staff_member_required
@require_http_methods(["GET"])
def industry_csv_template(request):
    """Download CSV template for Industry import"""
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="industry_template.csv"'
    
    writer = csv.writer(response)
    writer.writerow(['name', 'description', 'is_active'])
    writer.writerow(['Technology', 'Technology industry', 'true'])
    writer.writerow(['Healthcare', 'Healthcare and medical services', 'true'])
    
    return response


@staff_member_required
@require_http_methods(["POST"])
def industry_csv_import(request):
    """Import industries from CSV"""
    if not request.FILES.get('csv_file'):
        return JsonResponse({'success': False, 'error': 'No CSV file provided'}, status=400)
    
    csv_file = request.FILES['csv_file']
    decoded_file = csv_file.read().decode('utf-8')
    io_string = io.StringIO(decoded_file)
    reader = csv.DictReader(io_string)
    
    created = 0
    updated = 0
    errors = []
    
    from django.utils.text import slugify
    
    for row_num, row in enumerate(reader, start=2):
        try:
            is_active = row.get('is_active', 'true').lower() in ['true', '1', 'yes']
            slug = slugify(row['name'])
            
            industry, created_flag = Industry.objects.update_or_create(
                name=row['name'],
                defaults={
                    'slug': slug,
                    'description': row.get('description', ''),
                    'is_active': is_active
                }
            )
            if created_flag:
                created += 1
            else:
                updated += 1
        except Exception as e:
            errors.append(f"Row {row_num}: {str(e)}")
    
    return JsonResponse({
        'success': True,
        'created': created,
        'updated': updated,
        'errors': errors
    })


@staff_member_required
@require_http_methods(["GET"])
def industrysector_csv_template(request):
    """Download CSV template for IndustrySector import"""
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="industrysector_template.csv"'
    
    writer = csv.writer(response)
    writer.writerow(['name', 'industry', 'description', 'is_active'])
    writer.writerow(['Software Development', 'Technology', 'Software and app development', 'true'])
    writer.writerow(['Healthcare IT', 'Healthcare', 'Healthcare information technology', 'true'])
    
    return response


@staff_member_required
@require_http_methods(["POST"])
def industrysector_csv_import(request):
    """Import industry sectors from CSV"""
    if not request.FILES.get('csv_file'):
        return JsonResponse({'success': False, 'error': 'No CSV file provided'}, status=400)
    
    csv_file = request.FILES['csv_file']
    decoded_file = csv_file.read().decode('utf-8')
    io_string = io.StringIO(decoded_file)
    reader = csv.DictReader(io_string)
    
    created = 0
    updated = 0
    errors = []
    
    from django.utils.text import slugify
    
    for row_num, row in enumerate(reader, start=2):
        try:
            is_active = row.get('is_active', 'true').lower() in ['true', '1', 'yes']
            slug = slugify(row['name'])
            
            # Find industry by name
            try:
                industry = Industry.objects.get(name=row['industry'])
            except Industry.DoesNotExist:
                errors.append(f"Row {row_num}: Industry '{row['industry']}' not found")
                continue
            
            sector, created_flag = IndustrySector.objects.update_or_create(
                name=row['name'],
                industry=industry,
                defaults={
                    'slug': slug,
                    'description': row.get('description', ''),
                    'is_active': is_active
                }
            )
            if created_flag:
                created += 1
            else:
                updated += 1
        except Exception as e:
            errors.append(f"Row {row_num}: {str(e)}")
    
    return JsonResponse({
        'success': True,
        'created': created,
        'updated': updated,
        'errors': errors
    })


@staff_member_required
@require_http_methods(["GET"])
def seedkeyword_csv_template(request):
    """Download CSV template for SeedKeyword import"""
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="seedkeyword_template.csv"'
    
    writer = csv.writer(response)
    writer.writerow(['keyword', 'industry', 'sector', 'volume', 'difficulty', 'country', 'is_active'])
    writer.writerow(['python programming', 'Technology', 'Software Development', '10000', '45', 'US', 'true'])
    writer.writerow(['medical software', 'Healthcare', 'Healthcare IT', '5000', '60', 'CA', 'true'])
    
    return response


@staff_member_required
@require_http_methods(["POST"])
def seedkeyword_csv_import(request):
    """Import seed keywords from CSV"""
    if not request.FILES.get('csv_file'):
        return JsonResponse({'success': False, 'error': 'No CSV file provided'}, status=400)
    
    csv_file = request.FILES['csv_file']
    decoded_file = csv_file.read().decode('utf-8')
    io_string = io.StringIO(decoded_file)
    reader = csv.DictReader(io_string)
    
    created = 0
    updated = 0
    errors = []
    
    for row_num, row in enumerate(reader, start=2):
        try:
            is_active = row.get('is_active', 'true').lower() in ['true', '1', 'yes']
            
            # Find industry and sector by name
            try:
                industry = Industry.objects.get(name=row['industry'])
            except Industry.DoesNotExist:
                errors.append(f"Row {row_num}: Industry '{row['industry']}' not found")
                continue
            
            try:
                sector = IndustrySector.objects.get(name=row['sector'], industry=industry)
            except IndustrySector.DoesNotExist:
                errors.append(f"Row {row_num}: Sector '{row['sector']}' not found in industry '{row['industry']}'")
                continue
            
            keyword, created_flag = SeedKeyword.objects.update_or_create(
                keyword=row['keyword'],
                industry=industry,
                sector=sector,
                defaults={
                    'volume': int(row.get('volume', 0)),
                    'difficulty': int(row.get('difficulty', 0)),
                    'country': row.get('country', 'US'),
                    'is_active': is_active
                }
            )
            if created_flag:
                created += 1
            else:
                updated += 1
        except Exception as e:
            errors.append(f"Row {row_num}: {str(e)}")
    
    return JsonResponse({
        'success': True,
        'created': created,
        'updated': updated,
        'errors': errors
    })

