import { Request, Response } from 'express';
import prisma from '../../../config/database';
import { sendSuccess, sendError } from '../../../utils/response.utils';
import { AuthenticatedRequest } from '../../../middleware/auth.middleware';
import { encrypt, decrypt, maskSecret } from '../../../utils/encryption.utils';
import { ShippingProviderFactory } from '../services/shipping-provider.factory';
import { ShippingService } from '../services/shipping.service';
import { logger } from '../../../config/logger';

// 1. Get Admin Shipping Providers settings list
export const getAdminShippingProviders = async (req: AuthenticatedRequest, res: Response) => {
  try {
    if (res.locals.userRole !== 'ADMIN' && req.user?.role !== 'ADMIN') {
      return sendError(res, 'Forbidden', null, 403);
    }

    const providers = await prisma.shippingProvider.findMany({
      orderBy: { priority: 'asc' },
    });

    const maskedProviders = providers.map((p) => ({
      ...p,
      apiPassword: p.apiPassword ? maskSecret(p.apiPassword) : null,
      apiToken: p.apiToken ? maskSecret(p.apiToken) : null,
      clientSecret: p.clientSecret ? maskSecret(p.clientSecret) : null,
      secretKey: p.secretKey ? maskSecret(p.secretKey) : null,
    }));

    return sendSuccess(res, 'Admin shipping configurations loaded', { providers: maskedProviders });
  } catch (error: any) {
    return sendError(res, 'Failed to fetch shipping configurations', error.message, 500);
  }
};

// 2. Create Shipping Provider setting
export const createShippingProvider = async (req: AuthenticatedRequest, res: Response) => {
  try {
    const body = req.body;
    const provider = await prisma.shippingProvider.create({
      data: {
        providerName: body.providerName.toUpperCase(),
        displayName: body.displayName,
        isEnabled: body.isEnabled ?? true,
        environment: body.environment || 'sandbox',
        apiEmail: body.apiEmail,
        apiPassword: body.apiPassword ? encrypt(body.apiPassword) : null,
        apiToken: body.apiToken ? encrypt(body.apiToken) : null,
        clientId: body.clientId,
        clientSecret: body.clientSecret ? encrypt(body.clientSecret) : null,
        apiKey: body.apiKey,
        secretKey: body.secretKey ? encrypt(body.secretKey) : null,
        pickupLocation: body.pickupLocation,
        warehouseName: body.warehouseName,
        warehouseAddress: body.warehouseAddress,
        contactPerson: body.contactPerson,
        phone: body.phone,
        gstNumber: body.gstNumber,
        pincode: body.pincode,
        callbackUrl: body.callbackUrl,
        webhookUrl: body.webhookUrl,
        trackingUrl: body.trackingUrl,
        priority: body.priority ?? 0,
        defaultProvider: body.defaultProvider ?? false,
      },
    });

    return sendSuccess(res, 'Shipping provider added successfully', { id: provider.id });
  } catch (error: any) {
    return sendError(res, 'Failed to add shipping provider', error.message, 500);
  }
};

// 3. Update Shipping Provider settings
export const updateShippingProvider = async (req: AuthenticatedRequest, res: Response) => {
  try {
    const { id } = req.params;
    const body = req.body;

    const existing = await prisma.shippingProvider.findUnique({ where: { id } });
    if (!existing) return sendError(res, 'Provider configuration not found', null, 404);

    const apiPassword = body.apiPassword === '************' ? existing.apiPassword : (body.apiPassword ? encrypt(body.apiPassword) : null);
    const apiToken = body.apiToken === '************' ? existing.apiToken : (body.apiToken ? encrypt(body.apiToken) : null);
    const clientSecret = body.clientSecret === '************' ? existing.clientSecret : (body.clientSecret ? encrypt(body.clientSecret) : null);
    const secretKey = body.secretKey === '************' ? existing.secretKey : (body.secretKey ? encrypt(body.secretKey) : null);

    await prisma.shippingProvider.update({
      where: { id },
      data: {
        displayName: body.displayName,
        isEnabled: body.isEnabled,
        environment: body.environment,
        apiEmail: body.apiEmail,
        apiPassword,
        apiToken,
        clientId: body.clientId,
        clientSecret,
        apiKey: body.apiKey,
        secretKey,
        pickupLocation: body.pickupLocation,
        warehouseName: body.warehouseName,
        warehouseAddress: body.warehouseAddress,
        contactPerson: body.contactPerson,
        phone: body.phone,
        gstNumber: body.gstNumber,
        pincode: body.pincode,
        callbackUrl: body.callbackUrl,
        webhookUrl: body.webhookUrl,
        trackingUrl: body.trackingUrl,
        priority: body.priority,
        defaultProvider: body.defaultProvider,
      },
    });

    // Write audit log entry
    await prisma.shippingAudit.create({
      data: {
        providerId: id,
        action: 'PROVIDER_CONFIG_UPDATED',
        performedBy: req.user?.adminId || 'ADMIN',
        details: `Updated settings parameters for shipping provider: ${existing.providerName}`,
      },
    });

    return sendSuccess(res, 'Shipping provider updated successfully');
  } catch (error: any) {
    return sendError(res, 'Update failed', error.message, 500);
  }
};

// 4. Delete config
export const deleteShippingProvider = async (req: AuthenticatedRequest, res: Response) => {
  try {
    const { id } = req.params;
    await prisma.shippingProvider.delete({ where: { id } });
    return sendSuccess(res, 'Shipping provider settings deleted successfully');
  } catch (error: any) {
    return sendError(res, 'Deletion failed', error.message, 500);
  }
};

// 5. Toggle enable / disable status
export const toggleShippingProvider = async (req: AuthenticatedRequest, res: Response) => {
  try {
    const { id } = req.params;
    const existing = await prisma.shippingProvider.findUnique({ where: { id } });
    if (!existing) return sendError(res, 'Shipping provider not found', null, 404);

    const updated = await prisma.shippingProvider.update({
      where: { id },
      data: { isEnabled: !existing.isEnabled },
    });

    return sendSuccess(res, `Provider status toggled to: ${updated.isEnabled ? 'Enabled' : 'Disabled'}`, { isEnabled: updated.isEnabled });
  } catch (error: any) {
    return sendError(res, 'Toggle failed', error.message, 500);
  }
};

// 6. Test connection connectivity check
export const testShippingConnection = async (req: AuthenticatedRequest, res: Response) => {
  try {
    const { id } = req.params;
    const provider = await prisma.shippingProvider.findUnique({ where: { id } });
    if (!provider) return sendError(res, 'Shipping provider config not found', null, 404);

    const providerClient = await ShippingProviderFactory.getProvider(provider.providerName);
    const testResult = await providerClient.testConnection();

    logger.info(`Tested shipping connection for ${provider.providerName}: ${testResult.connected ? 'CONNECTED' : 'FAILED'}`);

    return sendSuccess(res, 'Tested connection parameters', {
      connected: testResult.connected,
      status: testResult.connected ? 'Connected' : 'Failed',
      message: testResult.message,
    });
  } catch (error: any) {
    return sendError(res, 'Connection validation check failed', error.message, 500);
  }
};

// 7. Create shipment dispatch
export const createShipment = async (req: Request, res: Response) => {
  try {
    const { orderId } = req.body;
    const shippingOrder = await ShippingService.syncOrderToShipping(orderId);
    return sendSuccess(res, 'Shipping order synced successfully', { shippingOrder });
  } catch (error: any) {
    return sendError(res, 'Failed to sync shipping order', error.message, 500);
  }
};

// 8. Generate AWB
export const generateAwb = async (req: Request, res: Response) => {
  try {
    const { shippingOrderId } = req.body;
    const updated = await ShippingService.generateAwb(shippingOrderId);
    return sendSuccess(res, 'AWB tracking number assigned successfully', { shippingOrder: updated });
  } catch (error: any) {
    return sendError(res, 'AWB generation failed', error.message, 500);
  }
};

// 9. Schedule Pickup
export const schedulePickup = async (req: Request, res: Response) => {
  try {
    const { shippingOrderId, pickupTime } = req.body;
    const pickup = await ShippingService.schedulePickup(shippingOrderId, new Date(pickupTime));
    return sendSuccess(res, 'Pickup scheduled successfully', { pickup });
  } catch (error: any) {
    return sendError(res, 'Pickup scheduling failed', error.message, 500);
  }
};

// 10. Cancel Shipment
export const cancelShipment = async (req: Request, res: Response) => {
  try {
    const { shippingOrderId } = req.body;
    const result = await ShippingService.cancelShipment(shippingOrderId);
    return sendSuccess(res, 'Shipment order cancelled successfully', result);
  } catch (error: any) {
    return sendError(res, 'Cancellation failed', error.message, 500);
  }
};

// 11. Track AWB realtime
export const trackShipment = async (req: Request, res: Response) => {
  try {
    const { trackingNumber } = req.params;
    const tracking = await ShippingService.trackShipment(trackingNumber);
    return sendSuccess(res, 'Shipment tracking timeline retrieved', { tracking });
  } catch (error: any) {
    return sendError(res, 'Real-time tracking fetch failed', error.message, 500);
  }
};
