// @ts-check
import crypto from 'node:crypto';
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
import { createWriteStream } from 'node:fs';
import { resolve, join } from 'node:path';
import { Readable } from 'node:stream';
import { pipeline } from 'node:stream/promises';

import stringify from 'json-stable-stringify-without-jsonify';

// Defines where the font lives
const DESIGN_SYSTEM_FONT_DIR = `./packages/design-system/public/_static/fonts/material-symbols`;
const WEB_FONT_DIR = `./apps/scandic-web/public/_static/fonts/material-symbols`;

// Defines the settings for the font
const FONT_BASE_URL = `https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0..1,0`;

// Defines the subset of icons for the font
const icons = [
  'accessibility',
  'accessible',
  'add',
  'add_circle',
  'air',
  'air_purifier_gen',
  'airline_seat_recline_normal',
  'airplane_ticket',
  'apartment',
  'apparel',
  'arrow_back',
  'arrow_forward',
  'arrow_right',
  'arrow_upward',
  'assistant_navigation',
  'asterisk',
  'attractions',
  'award_star',
  'bakery_dining',
  'balcony',
  'bathroom',
  'bathtub',
  'beach_access',
  'bed',
  'bedroom_parent',
  'box',
  'business_center',
  'calendar_add_on',
  'calendar_clock',
  'calendar_month',
  'calendar_today',
  'call',
  'call_quality',
  'camera',
  'cancel',
  'chair',
  'charging_station',
  'check',
  'check_box',
  'check_circle',
  'checked_bag',
  'checkroom',
  'chevron_left',
  'chevron_right',
  'close',
  'coffee',
  'coffee_maker',
  'compare_arrows',
  'computer',
  'concierge',
  'confirmation_number',
  'connected_tv',
  'content_copy',
  'contract',
  'cool_to_dry',
  'countertops',
  'credit_card',
  'credit_card_heart',
  'curtains',
  'curtains_closed',
  'deck',
  'delete',
  'desk',
  'device_thermostat',
  'diamond',
  'dining',
  'directions',
  'directions_run',
  'directions_subway',
  'downhill_skiing',
  'download',
  'dresser',
  'edit',
  'edit_calendar',
  'edit_square',
  'electric_bike',
  'electric_car',
  'elevator',
  'emoji_transportation',
  'error',
  'error_circle_rounded',
  'exercise',
  'family_restroom',
  'fastfood',
  'favorite',
  'fax',
  'featured_seasonal_and_gifts',
  'festival',
  'filter',
  'filter_alt',
  'floor_lamp',
  'forest',
  'garage',
  'globe',
  'golf_course',
  'groups',
  'health_and_beauty',
  'heat',
  'hiking',
  'home',
  'hot_tub',
  'houseboat',
  'hvac',
  'id_card',
  'imagesmode',
  'info',
  'iron',
  'kayaking',
  'kettle',
  'keyboard_arrow_down',
  'keyboard_arrow_up',
  'king_bed',
  'kitchen',
  'landscape',
  'laundry',
  'link',
  'liquor',
  'live_tv',
  'local_bar',
  'local_cafe',
  'local_convenience_store',
  'local_drink',
  'local_laundry_service',
  'local_parking',
  'location_city',
  'location_on',
  'lock',
  'loyalty',
  'luggage',
  'mail',
  'map',
  'meeting_room',
  'microwave',
  'mode_fan',
  'museum',
  'music_cast',
  'music_note',
  'nature',
  'night_shelter',
  'nightlife',
  'open_in_new',
  'pan_zoom',
  'panorama',
  'pedal_bike',
  'person',
  'pets',
  'phone',
  'pool',
  'print',
  'radio',
  'recommend',
  'redeem',
  'refresh',
  'remove',
  'restaurant',
  'room_service',
  'router',
  'sailing',
  'sauna',
  'scene',
  'search',
  'sell',
  'shopping_bag',
  'shower',
  'single_bed',
  'skateboarding',
  'smoke_free',
  'smoking_rooms',
  'spa',
  'sports_esports',
  'sports_golf',
  'sports_handball',
  'sports_tennis',
  'stairs',
  'star',
  'straighten',
  'styler',
  'support_agent',
  'swipe',
  'sync_saved_locally',
  'table_bar',
  'theater_comedy',
  'things_to_do',
  'train',
  'tram',
  'transit_ticket',
  'travel',
  'travel_luggage_and_bags',
  'tv_guide',
  'tv_remote',
  'upload',
  'visibility',
  'visibility_off',
  'ward',
  'warning',
  'water_full',
  'wifi',
  'yard',
].sort();

function createHash(value) {
  const stringified = stringify(value);
  const hash = crypto.createHash('sha256');
  hash.update(stringified);
  return hash.digest('hex');
}

const hash = createHash(icons).substring(0, 8);

async function fetchIconUrl(url) {
  const response = await fetch(url, {
    headers: {
      Accept:
        'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
      'User-Agent':
        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36',
    },
  });

  if (!response.ok) {
    console.error(`Unable to fetch woff2 for ${url}`);
    process.exit(1);
  }

  const text = await response.text();

  const isWoff2 = /format\('woff2'\)/.test(text);
  if (!isWoff2) {
    console.error(`Unable to identify woff2 font in response`);
    process.exit(1);
  }

  const srcUrl = text.match(/src: url\(([^)]+)\)/);

  if (srcUrl && srcUrl[1]) {
    return srcUrl[1];
  }

  return null;
}

async function download(url, destFolder) {
  const dest = resolve(join(destFolder, `/rounded-${hash}.woff2`));

  try {
    const response = await fetch(url);

    if (!response.ok) {
      console.error(`Unable to fetch ${url}`);
      process.exit(1);
    }

    if (!response.body) {
      console.error(`Bad response from ${url}`);
      process.exit(1);
    }

    const fileStream = createWriteStream(dest);

    // @ts-expect-error: type mismatch
    const readableNodeStream = Readable.fromWeb(response.body);

    await pipeline(readableNodeStream, fileStream);
  } catch (error) {
    console.error(`Error downloading file from ${url}:`, error);
    process.exit(1);
  }
}
async function cleanFontDirs(folderPath) {
  await rm(DESIGN_SYSTEM_FONT_DIR, { recursive: true, force: true });
  await mkdir(DESIGN_SYSTEM_FONT_DIR, { recursive: true });

  await rm(WEB_FONT_DIR, { recursive: true, force: true });
  await mkdir(WEB_FONT_DIR, { recursive: true });
}

async function updateFontCSS() {
  const file = './packages/design-system/lib/fonts.css';

  const css = await readFile(file, {
    encoding: 'utf-8',
  });

  await writeFile(
    file,
    css.replace(
      /url\(\/_static\/fonts\/material-symbols\/rounded[^)]+\)/,
      `url(/_static/fonts/material-symbols/rounded-${hash}.woff2)`
    ),
    {
      encoding: 'utf-8',
    }
  );
}

async function main() {
  const fontUrl = `${FONT_BASE_URL}&icon_names=${icons.join(',')}&display=block`;

  const iconUrl = await fetchIconUrl(fontUrl);

  if (iconUrl) {
    await cleanFontDirs();

    await download(iconUrl, DESIGN_SYSTEM_FONT_DIR);
    await download(iconUrl, WEB_FONT_DIR);

    await updateFontCSS();

    console.log('Successfully updated icons!');
    process.exit(0);
  } else {
    console.error(
      `Unable to find the icon font src URL in CSS response from Google Fonts at ${fontUrl}`
    );
  }
}

main();
