from datetime import datetime, timedelta, timezone, date
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
import pyotp
from fastapi import HTTPException, status

from src.Service.applicationservice import ApplicationService
from src.Service.companyService import CompanyService
from src.models.company_user import User
from src.models.company import Company
from src.models.application_user import ApplicationUser
from src.constants import UserType, CompanyPlanEnum

from src.external.email import transporter

#local utils
from .utils import (
encrypt_reset_payload,
decrypt_reset_token,
generate_qr_code_image,
create_jwt_access_token,
generate_password,
pwd_context

)

class CompanyUserAuthService(CompanyService):

    

    @staticmethod
    async def check_company_subscription(user: User, db: AsyncSession):
        stmt = select(Company).where(Company.id == user.company_id).limit(1)

        result = await db.execute(stmt)
        company = result.scalars().first()

        if not company:
            raise HTTPException(status_code=404, detail="Company not found")
        
        company_info = {
        "company_name": company.company_name,
        "legal_name": company.legal_name,
        "company_logo_url": company.company_logo_url,
        "next_billing_date": company.next_billing_date,        
        }

        
        if (not company.next_billing_date or company.next_billing_date.date() < date.today()) and (company.plan != CompanyPlanEnum.FREE):
            return {"company": company_info, "subscription_status": "expired"}
        
        return {"company": company_info, "subscription_status": "active"}

    @staticmethod
    async def user_login(email: str, password: str, db: AsyncSession):

        user = await CompanyUserAuthService.get_companyuser_by_email(email, db)
        
        result = await db.execute(
            select(Company).where(Company.company_name == user.company_name)
        )
        company = result.scalar_one_or_none()  # Returns None if not found
      
        if company.is_active is False:
            raise HTTPException(status_code=404, detail="Company is not active")
            


        
     
        if(user.is_active == False):
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="user is not active contact company IT admin"
            )


        if not pwd_context.verify(password, user.hashed_password):
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Incorrect password"
            )

        subscription_info = await CompanyUserAuthService.check_company_subscription(user, db)

        if subscription_info["subscription_status"] == "expired":
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail=subscription_info
            )

        if not user.system_password_reset:
            payload = {
                "userId": user.id,
                "expiresAt": (datetime.now(timezone.utc) + timedelta(minutes=10)).isoformat()
            }
            encrypted_token = encrypt_reset_payload(payload)
            user.password_reset_token = encrypted_token
            await db.commit()

            return {
                "password_reset_token": encrypted_token,
                "token_type": "password_reset",
            }

        if user.is_2FA_required == True and user.is_2FA_enabled == False:
        
            two_FA_setup_token = create_jwt_access_token(data={"user_id": user.id,"company_name":user.company_name,"company_id":user.company_id,"role":user.role,"department":user.department,"user_type":UserType.COMPANY},ACCESS_TOKEN_EXPIRE_MINUTES=20)
                    
            return {
                "2FA_setup_token": two_FA_setup_token,
                "token_type":"2FA_setup_token",
                "message":"user required two factor authentication setup complete the setup",
                "user_id":user.id,
                
                }

        if user.is_2FA_enabled == True:
            two_FA_login_token = create_jwt_access_token(data={"user_id": user.id,"company_name":user.company_name,"company_id":user.company_id,"role":user.role,"department":user.department,"user_type":UserType.COMPANY},ACCESS_TOKEN_EXPIRE_MINUTES=5)

            return {
                    "2FA_login_token": two_FA_login_token,
                    "token_type":"2FA_setup_login",
                    "message":"user required two factor authentication"
                    
                    }
        
        access_token = create_jwt_access_token(data={"user_id": user.id,"company_name":user.company_name,"company_id":user.company_id,"role":user.role,"department":user.department,"user_type":UserType.COMPANY})
    
        return {
                "access_token": access_token, 
                "token_type": "bearer",
                "user_role":user.role,
                "user_department":user.department,
                "company_name":user.company_name,
                "user_email":user.email,
                "user_name":user.full_name,
                "user_is_active":user.is_active,
                "Joined_on":user.created_at
                
                }
    

    async def request_reset_password(email:str,db:AsyncSession):
        user = await CompanyUserAuthService.get_companyuser_by_email(email, db)

        payload = {
            "userId": user.id,
            "expiresAt": (datetime.now(timezone.utc) + timedelta(minutes=10)).isoformat()
        }

        encrypted_token = encrypt_reset_payload(payload)
        print(encrypted_token)
        user.password_reset_token = encrypted_token
        await db.commit()
        
        reset_link = f"https://finsightai.mavenerp.in/reset-password/{encrypted_token}"
        logo_url="https://finsightai.mavenerp.in/assets/logo-transparent-png-CpxLVvxs.png"

        password_reset = f"""
                    <!DOCTYPE html>
                    <html>
                    <head>
                    <meta charset="UTF-8">
                    <title>Password Reset - FPnAInsights</title>
                    <style>
                    @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');
                    </style>
                    </head>
                    <body style="margin: 0; padding: 0; font-family: 'Inter', Arial, sans-serif; background-color: #f8fafc;">
                    <table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
                    <tr>
                        <td align="center" style="padding: 40px 0;">
                        <!-- Main Card -->
                        <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px; background: #ffffff; border-radius: 16px; box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08); overflow: hidden;">
                            <!-- Gradient Header -->
                            <tr>
                            <td style="height: 6px; background: linear-gradient(135deg, #38bdf8 0%, #0284c7 100%);"></td>
                            </tr>
                            
                            <!-- Content -->
                            <tr>
                            <td style="padding: 48px 48px 32px;">
                                <div style="text-align: center;">
                                <img src="{logo_url}" alt="FinsightAI Logo" style="height: 72px; margin-bottom: 24px;" />
                                
                                <h1 style="font-size: 22px; font-weight: 600; color: #0f172a; margin: 0 0 16px;">Hi {user.full_name},</h1>
                                
                                <p style="font-size: 15px; line-height: 1.6; color: #334155; margin: 0 0 32px;">
                                    We received a request to reset your FPnAInsights account password. Click the button below to securely reset your password:
                                </p>
                                
                                <!-- Primary Action Button -->
                                <table border="0" cellpadding="0" cellspacing="0" style="margin: 0 auto 32px;">
                                    <tr>
                                    <td align="center" style="border-radius: 8px;" bgcolor="#0284c7">
                                        <a href="{reset_link}" style="display: inline-block; padding: 16px 36px; font-size: 15px; font-weight: 500; color: #ffffff; text-decoration: none; border-radius: 8px; background: linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%); box-shadow: 0 2px 8px rgba(2, 132, 199, 0.25);">Reset Password</a>
                                    </td>
                                    </tr>
                                </table>
                                
                                <p style="font-size: 14px; color: #64748b; margin: 0 0 24px;">
                                    <strong>Note:</strong> This link expires in <span style="color: #dc2626; font-weight: 500;">10 minutes</span> for your security.
                                </p>
                                
                                <div style="border-top: 1px solid #e2e8f0; margin: 24px 0;"></div>
                                
                                <p style="font-size: 13px; color: #64748b; margin: 0;">
                                    If you didn't request this, please ignore this email or <a href="mailto:support@fpna.com" style="color: #0284c7; text-decoration: none;">contact our support team</a> if you have concerns.
                                </p>
                                </div>
                            </td>
                            </tr>
                            
                            <!-- Footer -->
                            <tr>
                            <td style="padding: 24px; background-color: #f1f5f9; text-align: center;">
                                <p style="font-size: 12px; color: #64748b; margin: 0;">
                                © 2025 FPnAInsights. All rights reserved.<br>
                                <span style="color: #94a3b8;">123 Business Ave, Suite 100, San Francisco, CA 94107</span>
                                </p>
                            </td>
                            </tr>
                        </table>
                        </td>
                    </tr>
                    </table>
                    </body>
                    </html>
                    """

        transporter.connect()
        transporter.send(
            user.email,
            "Password Reset Request",
            password_reset
        )
        transporter.close()

        return {"message": f"Password Reset Link sent to mail {user.email}", "action_type": "password_reset"}



    async def reset_password(encrypted_token:str,new_password,db:AsyncSession):

        payload = decrypt_reset_token(encrypted_token)
        user_id = payload['userId']
        expires_at = datetime.fromisoformat(payload['expiresAt'])

        if datetime.now(timezone.utc) > expires_at:
            raise HTTPException(status_code=400, detail="Token has expired")
        

        user = await CompanyUserAuthService.get_companyuser_by_id(user_id,db)


        if not user or user.password_reset_token != encrypted_token:
            raise HTTPException(status_code=400, detail="Invalid token")

        user.hashed_password = pwd_context.hash(new_password)
        user.system_password_reset = True 
        user.password_reset_token = None

        await db.commit()

        
        return {"message": "Password reset successfully"}
    
    async def setup_2fa(user_id:str, db):
        totp = pyotp.TOTP(pyotp.random_base32())

        user =  await CompanyUserAuthService.get_companyuser_by_id(user_id,db)

        otpauth_url = totp.provisioning_uri(name=user.email, issuer_name="finsightAI")

        user.temp_2fa_secret = totp.secret

        qr_data_base64 = generate_qr_code_image(otpauth_url)

        await db.commit()
        await db.refresh(user)

        return {
            "message": "Scan this QR code with Google Authenticator",
            "qr_code_base64": qr_data_base64,
        }
    
    async def verify_2fa(user_id:str,token: str,db: AsyncSession):

        user =  await CompanyUserAuthService.get_companyuser_by_id(user_id,db)
        print(user)

        if user.secret_2fa:
            raise HTTPException(status_code=400, detail={"message":"2FA is already enabled"})
        
        temp_secret = user.temp_2fa_secret


        if not temp_secret:
            raise HTTPException(status_code=400, detail="No temp_secret found setup 2fa first")

        totp = pyotp.TOTP(temp_secret)
        if totp.verify(token):
            
            user.secret_2fa = temp_secret  
            user.temp_2fa_secret = None  
            user.is_2FA_enabled = True
            
            await db.commit()
            await db.refresh(user)

            return {"verified": True, "message": "2FA is now enabled"}
        else:
            raise HTTPException(status_code=400, detail="Invalid token")

    async def login_2fa(user_id,two_FA_code,db):
        
        user = await CompanyUserAuthService.get_companyuser_by_id(user_id,db)

        secret = user.secret_2fa

        if not secret:
            raise HTTPException(status_code=400, detail="No 2FA secret found")

        totp = pyotp.TOTP(secret)
        if totp.verify(two_FA_code):

            access_token = create_jwt_access_token(data={"user_id": user.id,"company_name":user.company_name,"company_id":user.company_id,"role":user.role,"department":user.department,"user_type":UserType.COMPANY})

        
            return {"access_token": access_token, 
                "token_type": "bearer",
                "user_role":user.role,
                "user_department":user.department,
                "company_name":user.company_name,
                "user_email":user.email,
                "user_name":user.full_name,
                "user_is_active":user.is_active,
               "Joined_on":user.created_at
               }
        
        else:
            raise HTTPException(status_code=400, detail="Invalid token")
    
    async def enable_disable_two_factor_auth(user_id:str,current_company_user_company_id:str,db:AsyncSession):
        
        user = await CompanyUserAuthService.get_companyuser_by_id(user_id,db)
        #company_active=await 
        if(current_company_user_company_id != user.company_id):# checking in company level
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="user not found."
            )

        if(user.is_2FA_required == True):

            message = f"disabled two factor auth for user {user.full_name}"

            user.is_2FA_enabled = False
            user.is_2FA_required = False
            user.secret_2fa = None
            
        else:
            message = f"enabled two factor auth for user {user.full_name}"
            user.is_2FA_required = True



        await db.commit()
        await db.refresh(user)

        return {"message":message}


class ApplicationUserAuthService(ApplicationService):
    
     
    
     @staticmethod
     async def user_login(email: str, password: str, db: AsyncSession):

        user = await ApplicationUserAuthService.get_applicationuser_by_email(email, db)
        
        if not pwd_context.verify(password, user.hashed_password):
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Incorrect password"
            )
        
        access_token = create_jwt_access_token(data={"user_id": user.id,"role":user.role,"user_type":UserType.APPLICATION})

        return {"access_token": access_token, "token_type": "bearer","role":user.role}