import type { ActionFunctionArgs, LoaderFunction } from '@remix-run/node';
import { json } from '@remix-run/node';
import { createScopedLogger } from '~/lib/.server/logger';

// Only import child_process if we're not in a Cloudflare environment
let execSync: any;

const logger = createScopedLogger('api.system.disk-info');

try {
  // Check if we're in a Node.js environment
  if (typeof process !== 'undefined' && process.platform) {
    // Using dynamic import to avoid require()
    const childProcess = { execSync: null };
    execSync = childProcess.execSync;
  }
} catch {
  // In Cloudflare environment, this will fail, which is expected
  logger.debug('Running in Cloudflare environment, child_process not available');
}

// For development environments, we'll always provide mock data if real data isn't available
const isDevelopment = process.env.NODE_ENV === 'development';

interface DiskInfo {
  filesystem: string;
  size: number;
  used: number;
  available: number;
  percentage: number;
  mountpoint: string;
  timestamp: string;
  error?: string;
}

const getDiskInfo = (): DiskInfo[] => {
  // If we're in a Cloudflare environment and not in development, return error
  if (!execSync && !isDevelopment) {
    return [
      {
        filesystem: 'N/A',
        size: 0,
        used: 0,
        available: 0,
        percentage: 0,
        mountpoint: 'N/A',
        timestamp: new Date().toISOString(),
        error: 'Disk information is not available in this environment',
      },
    ];
  }

  // If we're in development but not in Node environment, return mock data
  if (!execSync && isDevelopment) {
    // Generate random percentage between 40-60%
    const percentage = Math.floor(40 + Math.random() * 20);
    const totalSize = 500 * 1024 * 1024 * 1024; // 500GB
    const usedSize = Math.floor((totalSize * percentage) / 100);
    const availableSize = totalSize - usedSize;

    return [
      {
        filesystem: 'MockDisk',
        size: totalSize,
        used: usedSize,
        available: availableSize,
        percentage,
        mountpoint: '/',
        timestamp: new Date().toISOString(),
      },
      {
        filesystem: 'MockDisk2',
        size: 1024 * 1024 * 1024 * 1024, // 1TB
        used: 300 * 1024 * 1024 * 1024, // 300GB
        available: 724 * 1024 * 1024 * 1024, // 724GB
        percentage: 30,
        mountpoint: '/data',
        timestamp: new Date().toISOString(),
      },
    ];
  }

  try {
    // Different commands for different operating systems
    const platform = process.platform;
    let disks: DiskInfo[] = [];

    if (platform === 'darwin') {
      // macOS - use df command to get disk information
      try {
        const output = execSync('df -k', { encoding: 'utf-8' }).toString().trim();

        // Skip the header line
        const lines = output.split('\n').slice(1);

        disks = lines.map((line: string) => {
          const parts = line.trim().split(/\s+/);
          const filesystem = parts[0];
          const size = parseInt(parts[1], 10) * 1024; // Convert KB to bytes
          const used = parseInt(parts[2], 10) * 1024;
          const available = parseInt(parts[3], 10) * 1024;
          const percentageStr = parts[4].replace('%', '');
          const percentage = parseInt(percentageStr, 10);
          const mountpoint = parts[5];

          return {
            filesystem,
            size,
            used,
            available,
            percentage,
            mountpoint,
            timestamp: new Date().toISOString(),
          };
        });

        // Filter out non-physical disks
        disks = disks.filter(
          (disk) =>
            !disk.filesystem.startsWith('devfs') &&
            !disk.filesystem.startsWith('map') &&
            !disk.mountpoint.startsWith('/System/Volumes') &&
            disk.size > 0,
        );
      } catch (error) {
        logger.error('Failed to get macOS disk info:', error);
        return [
          {
            filesystem: 'Unknown',
            size: 0,
            used: 0,
            available: 0,
            percentage: 0,
            mountpoint: '/',
            timestamp: new Date().toISOString(),
            error: error instanceof Error ? error.message : 'Unknown error',
          },
        ];
      }
    } else if (platform === 'linux') {
      // Linux - use df command to get disk information
      try {
        const output = execSync('df -k', { encoding: 'utf-8' }).toString().trim();

        // Skip the header line
        const lines = output.split('\n').slice(1);

        disks = lines.map((line: string) => {
          const parts = line.trim().split(/\s+/);
          const filesystem = parts[0];
          const size = parseInt(parts[1], 10) * 1024; // Convert KB to bytes
          const used = parseInt(parts[2], 10) * 1024;
          const available = parseInt(parts[3], 10) * 1024;
          const percentageStr = parts[4].replace('%', '');
          const percentage = parseInt(percentageStr, 10);
          const mountpoint = parts[5];

          return {
            filesystem,
            size,
            used,
            available,
            percentage,
            mountpoint,
            timestamp: new Date().toISOString(),
          };
        });

        // Filter out non-physical disks
        disks = disks.filter(
          (disk) =>
            !disk.filesystem.startsWith('/dev/loop') &&
            !disk.filesystem.startsWith('tmpfs') &&
            !disk.filesystem.startsWith('devtmpfs') &&
            disk.size > 0,
        );
      } catch (error) {
        logger.error('Failed to get Linux disk info:', error);
        return [
          {
            filesystem: 'Unknown',
            size: 0,
            used: 0,
            available: 0,
            percentage: 0,
            mountpoint: '/',
            timestamp: new Date().toISOString(),
            error: error instanceof Error ? error.message : 'Unknown error',
          },
        ];
      }
    } else if (platform === 'win32') {
      // Windows - use PowerShell to get disk information
      try {
        const output = execSync(
          'powershell "Get-PSDrive -PSProvider FileSystem | Select-Object Name, Used, Free, @{Name=\'Size\';Expression={$_.Used + $_.Free}} | ConvertTo-Json"',
          { encoding: 'utf-8' },
        )
          .toString()
          .trim();

        const driveData = JSON.parse(output);
        const drivesArray = Array.isArray(driveData) ? driveData : [driveData];

        disks = drivesArray.map((drive) => {
          const size = drive.Size || 0;
          const used = drive.Used || 0;
          const available = drive.Free || 0;
          const percentage = size > 0 ? Math.round((used / size) * 100) : 0;

          return {
            filesystem: drive.Name + ':\\',
            size,
            used,
            available,
            percentage,
            mountpoint: drive.Name + ':\\',
            timestamp: new Date().toISOString(),
          };
        });
      } catch (error) {
        logger.error('Failed to get Windows disk info:', error);
        return [
          {
            filesystem: 'Unknown',
            size: 0,
            used: 0,
            available: 0,
            percentage: 0,
            mountpoint: 'C:\\',
            timestamp: new Date().toISOString(),
            error: error instanceof Error ? error.message : 'Unknown error',
          },
        ];
      }
    } else {
      logger.warn(`Unsupported platform: ${platform}`);
      return [
        {
          filesystem: 'Unknown',
          size: 0,
          used: 0,
          available: 0,
          percentage: 0,
          mountpoint: '/',
          timestamp: new Date().toISOString(),
          error: `Unsupported platform: ${platform}`,
        },
      ];
    }

    return disks;
  } catch (error) {
    logger.error('Failed to get disk info:', error);
    return [
      {
        filesystem: 'Unknown',
        size: 0,
        used: 0,
        available: 0,
        percentage: 0,
        mountpoint: '/',
        timestamp: new Date().toISOString(),
        error: error instanceof Error ? error.message : 'Unknown error',
      },
    ];
  }
};

export const diskLoader: LoaderFunction = async ({ request: _request }) => {
  try {
    return json(getDiskInfo());
  } catch (error) {
    logger.error('Failed to get disk info:', error);
    return json(
      [
        {
          filesystem: 'Unknown',
          size: 0,
          used: 0,
          available: 0,
          percentage: 0,
          mountpoint: '/',
          timestamp: new Date().toISOString(),
          error: error instanceof Error ? error.message : 'Unknown error',
        },
      ],
      { status: 500 },
    );
  }
};

export const diskAction = async ({ request: _request }: ActionFunctionArgs) => {
  try {
    return json(getDiskInfo());
  } catch (error) {
    logger.error('Failed to get disk info:', error);
    return json(
      [
        {
          filesystem: 'Unknown',
          size: 0,
          used: 0,
          available: 0,
          percentage: 0,
          mountpoint: '/',
          timestamp: new Date().toISOString(),
          error: error instanceof Error ? error.message : 'Unknown error',
        },
      ],
      { status: 500 },
    );
  }
};
