/**
 * Dataroom Service
 * Handles secure VDR, deal rooms, and document access control
 */

import Fastify, { type FastifyRequest, type FastifyReply } from 'fastify';
import fastifySwagger from '@fastify/swagger';
import fastifySwaggerUI from '@fastify/swagger-ui';
import {
  errorHandler,
  createLogger,
  registerSecurityPlugins,
  addCorrelationId,
  addRequestLogging,
  getEnv,
  createBodySchema,
  authenticateJWT,
  requireRole,
} from '@the-order/shared';
import { CreateDealSchema, CreateDocumentSchema } from '@the-order/schemas';
import { StorageClient } from '@the-order/storage';
import {
  getPool,
  createDeal,
  getDealById,
  createDealDocument,
  createDocument,
} from '@the-order/database';
import { randomUUID } from 'crypto';

const logger = createLogger('dataroom-service');

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const server: any = Fastify({
  logger: logger as any,
  requestIdLogLabel: 'requestId',
  disableRequestLogging: false,
});

// Initialize database pool
const env = getEnv();
if (env.DATABASE_URL) {
  getPool({ connectionString: env.DATABASE_URL });
}

// Initialize storage client
const storageClient = new StorageClient({
  provider: env.STORAGE_TYPE || 's3',
  bucket: env.STORAGE_BUCKET,
  region: env.STORAGE_REGION,
});

// Initialize server
async function initializeServer(): Promise<void> {
  // Register Swagger
  const swaggerUrl = env.SWAGGER_SERVER_URL || (env.NODE_ENV === 'development' ? 'http://localhost:4004' : undefined);
  if (!swaggerUrl) {
    logger.warn('SWAGGER_SERVER_URL not set, Swagger documentation will not be available');
  } else {
    await server.register(fastifySwagger, {
      openapi: {
        info: {
          title: 'Dataroom Service API',
          description: 'Secure VDR, deal rooms, and document access control',
          version: '1.0.0',
        },
        servers: [
          {
            url: swaggerUrl,
            description: env.NODE_ENV || 'Development server',
          },
        ],
      },
    });

    await server.register(fastifySwaggerUI, {
      routePrefix: '/docs',
    });
  }

  await registerSecurityPlugins(server as any);
  addCorrelationId(server as any);
  addRequestLogging(server as any);
  server.setErrorHandler(errorHandler as any);
}

// Health check
server.get(
  '/health',
  {
    schema: {
      description: 'Health check endpoint',
      tags: ['health'],
      response: {
        200: {
          type: 'object',
          properties: {
            status: { type: 'string' },
            service: { type: 'string' },
            database: { type: 'string' },
            storage: { type: 'string' },
          },
        },
      },
    },
  },
  async () => {
    const { healthCheck: dbHealthCheck } = await import('@the-order/database');
    const dbHealthy = await dbHealthCheck().catch(() => false);
    const storageHealthy = await storageClient.objectExists('health-check').catch(() => false);

    return {
      status: dbHealthy && storageHealthy ? 'ok' : 'degraded',
      service: 'dataroom',
      database: dbHealthy ? 'connected' : 'disconnected',
      storage: storageHealthy ? 'accessible' : 'unavailable',
    };
  }
);

// Create deal room
server.post(
  '/deals',
  {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    preHandler: [authenticateJWT as any, requireRole('admin', 'deal_manager') as any],
    schema: {
      ...createBodySchema(CreateDealSchema),
      description: 'Create a new deal room',
      tags: ['deals'],
      response: {
        201: {
          type: 'object',
          properties: {
            deal: {
              type: 'object',
            },
          },
        },
      },
    },
  },
  async (request: FastifyRequest, reply: FastifyReply) => {
    const body = request.body as { name: string; status?: string };
    const userId = (request as any).user?.id;
    
    const deal = await createDeal({
      name: body.name,
      status: body.status || 'draft',
      dataroom_id: randomUUID(),
      created_by: userId,
    });

    return reply.status(201).send({ deal });
  }
);

// Get deal room
server.get(
  '/deals/:dealId',
  {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    preHandler: [authenticateJWT as any],
    schema: {
      description: 'Get a deal room by ID',
      tags: ['deals'],
      params: {
        type: 'object',
        required: ['dealId'],
        properties: {
          dealId: { type: 'string', format: 'uuid' },
        },
      },
      response: {
        200: {
          type: 'object',
          properties: {
            deal: {
              type: 'object',
            },
          },
        },
      },
    },
  },
  async (request: FastifyRequest, reply: FastifyReply) => {
    const { dealId } = request.params as { dealId: string };
    
    const deal = await getDealById(dealId);
    if (!deal) {
      return reply.status(404).send({ error: { code: 'NOT_FOUND', message: 'Deal not found' } });
    }

    return { deal };
  }
);

// Upload document to deal room
server.post(
  '/deals/:dealId/documents',
  {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    preHandler: [authenticateJWT as any, requireRole('admin', 'deal_manager', 'editor') as any],
    schema: {
      ...createBodySchema(CreateDocumentSchema),
      description: 'Upload a document to a deal room',
      tags: ['documents'],
      params: {
        type: 'object',
        required: ['dealId'],
        properties: {
          dealId: { type: 'string', format: 'uuid' },
        },
      },
      response: {
        201: {
          type: 'object',
          properties: {
            document: {
              type: 'object',
            },
          },
        },
      },
    },
  },
  async (request: FastifyRequest, reply: FastifyReply) => {
    const { dealId } = request.params as { dealId: string };
    const body = request.body as { title: string; type: string; content?: string; fileUrl?: string };
    const userId = (request as any).user?.id;
    
    // Verify deal exists
    const deal = await getDealById(dealId);
    if (!deal) {
      return reply.status(404).send({ error: { code: 'NOT_FOUND', message: 'Deal not found' } });
    }

    const documentId = randomUUID();
    const key = `deals/${dealId}/documents/${documentId}`;

    // Upload to storage if content provided
    if (body.content) {
      await storageClient.upload({
        key,
        content: Buffer.from(body.content),
        contentType: 'application/pdf',
        metadata: {
          dealId,
          title: body.title,
          type: body.type,
        },
      });
    }

    // Save document to database
    const document = await createDocument({
      title: body.title,
      type: body.type,
      file_url: body.fileUrl || key,
      storage_key: body.content ? key : undefined,
      user_id: userId,
      status: 'active',
    });

    // Link document to deal
    await createDealDocument(dealId, document.id, key);

    return reply.status(201).send({ document });
  }
);

// Get presigned URL for document access
server.get(
  '/deals/:dealId/documents/:documentId/url',
  {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    preHandler: [authenticateJWT as any],
    schema: {
      description: 'Get a presigned URL for document access',
      tags: ['documents'],
      params: {
        type: 'object',
        required: ['dealId', 'documentId'],
        properties: {
          dealId: { type: 'string', format: 'uuid' },
          documentId: { type: 'string', format: 'uuid' },
        },
      },
      querystring: {
        type: 'object',
        properties: {
          expiresIn: { type: 'number', default: 3600 },
        },
      },
      response: {
        200: {
          type: 'object',
          properties: {
            url: { type: 'string', format: 'uri' },
            expiresIn: { type: 'number' },
          },
        },
      },
    },
  },
  async (request: FastifyRequest, _reply: FastifyReply) => {
    const { dealId, documentId } = request.params as { dealId: string; documentId: string };
    const { expiresIn = 3600 } = request.query as { expiresIn?: number };
    
    const key = `deals/${dealId}/documents/${documentId}`;
    const url = await storageClient.getPresignedUrl(key, expiresIn);

    return { url, expiresIn };
  }
);

// Start server
const start = async () => {
  try {
    await initializeServer();
    const env = getEnv();
    const port = env.PORT || 4004;
    await server.listen({ port, host: '0.0.0.0' });
    logger.info({ port }, 'Dataroom service listening');
  } catch (err) {
    logger.error({ err }, 'Failed to start server');
    process.exit(1);
  }
};

start();

