import { Hono } from 'hono';
import { serveStatic } from 'hono/bun';
import { cors } from 'hono/cors';
import path from 'path';
import { fileURLToPath } from 'url';
import { readFile } from 'fs/promises';
import { existsSync } from 'fs';
import { AuthConfigManager, BackendAuth } from '../auth-module/backend';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

const app = new Hono();
const PORT = process.env.PORT || 3005;

// Initialize auth
const backendAuth = new BackendAuth({
  clientId: process.env.CLIENT_ID,
  tenantId: process.env.TENANT_ID,
  clientSecret: process.env.CLIENT_SECRET,
}, process.env.PB_DB);

// CORS Configuration - Allow requests from frontend domains
app.use('*', cors({
  origin: ['https://ji-test.ccllc.pro', 'http://localhost:3005', 'http://localhost:5173'],
  allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
}));

// Serve bundled auth module JavaScript
app.get('/auth-module.js', async (c) => {
  const filePath = path.join(__dirname, '../frontend/dist/auth.js');
  if (existsSync(filePath)) {
    const content = await readFile(filePath);
    c.header('Content-Type', 'application/javascript');
    return c.body(content);
  }
  return c.notFound();
});

// Serve frontend static files
app.use('/', serveStatic({ root: path.join(__dirname, '../frontend') }));

// API: Get frontend config
app.get('/api/auth/config', (c) => {
  try {
    const config = AuthConfigManager.getFrontendConfig();
    return c.json(config);
  } catch (error) {
    return c.json(
      { error: 'Failed to get config', message: error instanceof Error ? error.message : 'Unknown error' },
      500
    );
  }
});

// API: Get Graph token status
app.get('/api/auth/graph/token', async (c) => {
  try {
    const { token, expiresOnISO } = await backendAuth.graphTokenManager.getTokenWithExpiry();
    
    if (!token) {
      return c.json({ success: false, error: 'Failed to acquire Graph token' }, 500);
    }
    
    // Decode JWT to show token details (for verification)
    const parts = token.split('.');
    let payload = {};
    if (parts.length === 3) {
      try {
        const decoded = JSON.parse(Buffer.from(parts[1], 'base64').toString());
        payload = {
          aud: decoded.aud,
          iss: decoded.iss,
          scp: decoded.scp,
          app_displayname: decoded.app_displayname,
          iat: new Date(decoded.iat * 1000).toISOString(),
          exp: new Date(decoded.exp * 1000).toISOString(),
        };
      } catch (e) {
        // Silent fail - just show truncated token
      }
    }
    
    return c.json({
      success: true,
      token: token.substring(0, 50) + '...',
      fullToken: token, // Include full token for testing
      expiresOn: expiresOnISO,
      isValid: backendAuth.graphTokenManager.isTokenValid(),
      tokenDetails: Object.keys(payload).length > 0 ? payload : 'Could not decode',
    });
  } catch (error) {
    return c.json(
      { success: false, error: error instanceof Error ? error.message : 'Failed to acquire token' },
      500
    );
  }
});

// API: Validate PocketBase token
app.post('/api/auth/validate-pb-token', async (c) => {
  try {
    const body = await c.req.json();
    const token = body.pbToken;

    if (!token) {
      return c.json({ valid: false, error: 'No token provided' }, 400);
    }

    const isValid = await backendAuth.pbValidator.validateUserToken(token);
    const user = isValid ? await backendAuth.pbValidator.getUserRecord(token) : null;

    return c.json({
      valid: isValid,
      user: user ? {
        id: user.id,
        email: user.email,
        name: user.name,
      } : null,
    });
  } catch (error) {
    return c.json(
      { valid: false, error: error instanceof Error ? error.message : 'Validation failed' },
      500
    );
  }
});

// API: Refresh Graph token (test cache)
app.post('/api/auth/refresh-graph', async (c) => {
  try {
    backendAuth.graphTokenManager.clearCache();
    const { token, expiresOnISO } = await backendAuth.graphTokenManager.getTokenWithExpiry();
    return c.json({
      success: true,
      refreshed: true,
      expiresOn: expiresOnISO,
    });
  } catch (error) {
    return c.json(
      { success: false, error: error instanceof Error ? error.message : 'Refresh failed' },
      500
    );
  }
});

// API: Compare PB and Graph tokens
app.post('/api/auth/compare-tokens', async (c) => {
  try {
    const body = await c.req.json();
    const pbToken = body.pbToken;
    
    // Get Graph token
    const { token: graphToken, expiresOnISO: graphExpires } = await backendAuth.graphTokenManager.getTokenWithExpiry();
    
    if (!graphToken) {
      return c.json({ success: false, error: 'Failed to acquire Graph token' }, 500);
    }
    
    // Decode both tokens to compare
    const decodeJWT = (token: string) => {
      try {
        const parts = token.split('.');
        if (parts.length !== 3) return null;
        return JSON.parse(Buffer.from(parts[1], 'base64').toString());
      } catch {
        return null;
      }
    };

    const graphPayload = decodeJWT(graphToken);
    
    // Validate PB token to get actual user
    let authenticatedUser = 'Unknown';
    if (pbToken) {
      try {
        const isValid = await backendAuth.pbValidator.validateUserToken(pbToken);
        if (isValid) {
          const userRecord = await backendAuth.pbValidator.getUserRecord(pbToken);
          authenticatedUser = userRecord?.email || userRecord?.id || 'Unknown';
        }
      } catch {
        authenticatedUser = 'Token invalid or expired';
      }
    }
    
    return c.json({
      success: true,
      comparison: {
        graph_token: {
          issuer: graphPayload?.iss || 'N/A',
          audience: graphPayload?.aud || 'N/A',
          app: graphPayload?.app_displayname || 'N/A',
          scopes: graphPayload?.scp || 'N/A',
          issued_at: graphPayload?.iat ? new Date(graphPayload.iat * 1000).toISOString() : 'N/A',
          expires_at: graphPayload?.exp ? new Date(graphPayload.exp * 1000).toISOString() : 'N/A',
          type: 'Microsoft Graph Token (Backend/App-only)',
          source: '@azure/msal-node',
          purpose: 'Backend API calls to Microsoft Graph',
        },
        pocketbase_token: {
          note: 'User token from PocketBase OAuth2',
          type: 'PocketBase User Token (Frontend/User)',
          source: 'PocketBase OAuth2 flow',
          purpose: 'User authentication and authorization',
          authenticated_user: authenticatedUser,
        },
        are_different: true,
        explanation: 'These are completely different tokens from different systems: Graph token is for app-to-app Microsoft API access, PocketBase token is for user authentication in the application.',
      },
    });
  } catch (error) {
    return c.json(
      { success: false, error: error instanceof Error ? error.message : 'Failed to compare tokens' },
      500
    );
  }
});

// Start server
console.log(`Mode1 Auth Test Server running on port ${PORT}`);
export default {
  port: PORT,
  fetch: app.fetch,
};
