import { WebSocketServer, WebSocket } from 'ws';
import { Server } from 'http';
import { verifyAuth } from "./auth.ts";

interface AdminNotification {
  type: 'shift_assignment' | 'delegation_approval' | 'knowledge_update' | 'admin_action' | 'system_alert';
  title: string;
  content: string;
  severity: 'info' | 'warning' | 'error' | 'success';
  timestamp: number;
  data?: Record<string, any>;
}

interface AdminConnection {
  ws: WebSocket;
  userId: string;
  role: string;
  connectedAt: number;
}

const adminConnections = new Map<string, AdminConnection[]>();

export function setupWebSocketServer(httpServer: Server) {
  const wss = new WebSocketServer({ server: httpServer, path: '/api/ws/admin' });

  wss.on('connection', async (ws: WebSocket, req) => {
    try {
      // Extract auth token from query params
      const url = new URL(req.url || '', `http://${req.headers.host}`);
      const token = url.searchParams.get('token');

      if (!token) {
        ws.close(1008, 'Unauthorized: No token provided');
        return;
      }

      // Verify authentication
      const auth = await verifyAuth(token);
      if (!auth || !auth.user) {
        ws.close(1008, 'Unauthorized: Invalid token');
        return;
      }

      // Check admin role
      if (auth.user.role !== 'admin') {
        ws.close(1008, 'Forbidden: Admin access required');
        return;
      }

      const userId = auth.user.id;
      const connection: AdminConnection = {
        ws,
        userId,
        role: auth.user.role,
        connectedAt: Date.now(),
      };

      // Store connection
      if (!adminConnections.has(userId)) {
        adminConnections.set(userId, []);
      }
      adminConnections.get(userId)!.push(connection);

      console.log(`[WS] Admin ${userId} connected. Total connections: ${adminConnections.size}`);

      // Send welcome message
      ws.send(JSON.stringify({
        type: 'connection_established',
        message: 'Connected to admin notifications',
        timestamp: Date.now(),
      }));

      // Handle incoming messages
      ws.on('message', (data: Buffer) => {
        try {
          const message = JSON.parse(data.toString());
          handleAdminMessage(userId, message, ws);
        } catch (error) {
          console.error('[WS] Error parsing message:', error);
          ws.send(JSON.stringify({
            type: 'error',
            message: 'Invalid message format',
            timestamp: Date.now(),
          }));
        }
      });

      // Handle disconnection
      ws.on('close', () => {
        const connections = adminConnections.get(userId);
        if (connections) {
          const index = connections.indexOf(connection);
          if (index > -1) {
            connections.splice(index, 1);
          }
          if (connections.length === 0) {
            adminConnections.delete(userId);
          }
        }
        console.log(`[WS] Admin ${userId} disconnected`);
      });

      // Handle errors
      ws.on('error', (error) => {
        console.error('[WS] Connection error:', error);
      });
    } catch (error) {
      console.error('[WS] Connection setup error:', error);
      ws.close(1011, 'Internal server error');
    }
  });

  return wss;
}

function handleAdminMessage(userId: string, message: any, ws: WebSocket) {
  switch (message.type) {
    case 'ping':
      ws.send(JSON.stringify({ type: 'pong', timestamp: Date.now() }));
      break;
    case 'subscribe':
      // Admin can subscribe to specific event types
      console.log(`[WS] Admin ${userId} subscribed to: ${message.events?.join(', ')}`);
      ws.send(JSON.stringify({
        type: 'subscription_confirmed',
        events: message.events,
        timestamp: Date.now(),
      }));
      break;
    default:
      console.log(`[WS] Unknown message type: ${message.type}`);
  }
}

export function broadcastToAdmins(notification: AdminNotification, targetAdminIds?: string[]) {
  const payload = JSON.stringify(notification);
  let broadcastCount = 0;

  if (targetAdminIds && targetAdminIds.length > 0) {
    // Send to specific admins
    targetAdminIds.forEach((adminId) => {
      const connections = adminConnections.get(adminId);
      if (connections) {
        connections.forEach((conn) => {
          if (conn.ws.readyState === WebSocket.OPEN) {
            conn.ws.send(payload);
            broadcastCount++;
          }
        });
      }
    });
  } else {
    // Broadcast to all connected admins
    adminConnections.forEach((connections) => {
      connections.forEach((conn) => {
        if (conn.ws.readyState === WebSocket.OPEN) {
          conn.ws.send(payload);
          broadcastCount++;
        }
      });
    });
  }

  console.log(`[WS] Broadcast notification to ${broadcastCount} admin connections`);
  return broadcastCount;
}

export function notifyShiftAssignment(shiftId: string, assignedTo: string, assignedBy: string) {
  broadcastToAdmins({
    type: 'shift_assignment',
    title: 'Shift Assignment',
    content: `New shift assigned to ${assignedTo}`,
    severity: 'info',
    timestamp: Date.now(),
    data: { shiftId, assignedTo, assignedBy },
  });
}

export function notifyDelegationApproval(delegationId: string, status: 'approved' | 'rejected', approvedBy: string) {
  broadcastToAdmins({
    type: 'delegation_approval',
    title: `Delegation ${status === 'approved' ? 'Approved' : 'Rejected'}`,
    content: `Delegation #${delegationId} has been ${status}`,
    severity: status === 'approved' ? 'success' : 'warning',
    timestamp: Date.now(),
    data: { delegationId, status, approvedBy },
  });
}

export function notifyKnowledgeUpdate(articleId: string, action: 'created' | 'updated' | 'published', title: string) {
  broadcastToAdmins({
    type: 'knowledge_update',
    title: `Knowledge Base ${action === 'created' ? 'Article Created' : action === 'updated' ? 'Article Updated' : 'Article Published'}`,
    content: `${title}`,
    severity: 'info',
    timestamp: Date.now(),
    data: { articleId, action, title },
  });
}

export function notifyAdminAction(action: string, details: string, adminId: string) {
  broadcastToAdmins({
    type: 'admin_action',
    title: 'Admin Action',
    content: `${action}: ${details}`,
    severity: 'info',
    timestamp: Date.now(),
    data: { action, details, adminId },
  });
}

export function notifySystemAlert(title: string, content: string, severity: 'info' | 'warning' | 'error' = 'warning') {
  broadcastToAdmins({
    type: 'system_alert',
    title,
    content,
    severity,
    timestamp: Date.now(),
  });
}
