import fs from 'fs/promises';
import path from 'path';
import DesktopRelease, { PLATFORMS, Platform } from '../models/desktopRelease';

const DOWNLOADS_DIR = path.join(__dirname, '..', '..', 'downloads');

const badRequest = (msg: string): Error & { statusCode: number } =>
  Object.assign(new Error(msg), { statusCode: 400 });

const notFound = (msg: string): Error & { statusCode: number } =>
  Object.assign(new Error(msg), { statusCode: 404 });

const VERSION_PATTERN = /^\d+(\.\d+){1,3}(-[0-9A-Za-z.]+)?$/;

const EXTENSIONS_BY_PLATFORM: Record<Platform, string[]> = {
  windows: ['.exe'],
  macos: ['.dmg', '.pkg'],
  linux: ['.appimage', '.deb', '.rpm'],
};

const parseBoolean = (value: unknown): boolean => value === true || value === 'true';

const parsePlatform = (value: unknown, fallback: Platform = 'windows'): Platform => {
  if (typeof value !== 'string' || !value.trim()) return fallback;
  const platform = value.trim().toLowerCase();
  if (!PLATFORMS.includes(platform as Platform)) {
    throw badRequest(`platform must be one of ${PLATFORMS.join(', ')}`);
  }
  return platform as Platform;
};

const parseReleaseNotes = (value: unknown): string[] => {
  if (Array.isArray(value)) {
    return value.map((note) => String(note).trim()).filter(Boolean);
  }
  if (typeof value === 'string') {
    return value
      .split('\n')
      .map((note) => note.trim())
      .filter(Boolean);
  }
  return [];
};

export const createDesktopRelease = async (
  payload: { version?: string; platform?: unknown; release_notes?: unknown; mandatory?: unknown; is_active?: unknown },
  file?: { buffer: Buffer; size: number; originalname: string },
) => {
  const version = payload.version?.trim();
  if (!version) throw badRequest('version is required');
  if (!VERSION_PATTERN.test(version)) throw badRequest('version must look like 1.0.1');
  if (!file) throw badRequest('installer file is required');

  const platform = parsePlatform(payload.platform);
  const ext = path.extname(file.originalname).toLowerCase();
  if (!EXTENSIONS_BY_PLATFORM[platform].includes(ext)) {
    throw badRequest(`Installer for platform "${platform}" must be one of: ${EXTENSIONS_BY_PLATFORM[platform].join(', ')}`);
  }

  const existing = await DesktopRelease.findOne({ version, platform }).lean();
  if (existing) throw badRequest(`A ${platform} release with version ${version} already exists`);

  const release_notes = parseReleaseNotes(payload.release_notes);
  const mandatory = parseBoolean(payload.mandatory);
  const is_active = parseBoolean(payload.is_active);
  const installer_filename = `EGInTimeSetup_${platform}_v${version}${ext}`;

  await fs.mkdir(DOWNLOADS_DIR, { recursive: true });
  await fs.writeFile(path.join(DOWNLOADS_DIR, installer_filename), file.buffer);

  try {
    if (is_active) {
      await DesktopRelease.updateMany({ is_active: true, platform }, { is_active: false });
    }

    const release = await DesktopRelease.create({
      version,
      platform,
      installer_filename,
      original_filename: file.originalname,
      release_notes,
      mandatory,
      is_active,
      file_size: file.size,
    });

    return release;
  } catch (error) {
    await fs.unlink(path.join(DOWNLOADS_DIR, installer_filename)).catch(() => undefined);
    throw error;
  }
};

export const getAllDesktopReleases = async () => {
  return DesktopRelease.find().sort({ release_date: -1 }).lean();
};

export const getLatestActiveDesktopRelease = async (platformInput?: unknown) => {
  const platform = parsePlatform(platformInput);
  const release = await DesktopRelease.findOne({ is_active: true, platform }).sort({ release_date: -1 }).lean();
  if (!release) throw notFound(`No active desktop release found for platform ${platform}`);
  return release;
};

export const deleteDesktopRelease = async (id: string) => {
  const release = await DesktopRelease.findById(id);
  if (!release) throw notFound('Desktop release not found');

  await fs.unlink(path.join(DOWNLOADS_DIR, release.installer_filename)).catch(() => undefined);
  await release.deleteOne();

  return release;
};

export const resolveInstallerPath = (fileName: string): string => {
  const safeName = path.basename(fileName);
  if (safeName !== fileName) throw badRequest('Invalid file name');
  return path.join(DOWNLOADS_DIR, safeName);
};
