// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
import { protocol } from 'electron';

import type { OptionalResourceService } from './OptionalResourceService.main.ts';
import { getAppRootDir } from '../ts/util/appRootDir.main.ts';
import * as Errors from '../ts/types/errors.std.ts';
import { createLogger } from '../ts/logging/log.std.ts';

const log = createLogger('AssetService');

const LOCAL_ASSETS = new Set([
  'fonts/signal-symbols/SignalSymbolsVariable.woff2',
  'fonts/stories/Hatsuishi-Regular.woff2',
  'fonts/stories/EBGaramond-Regular.ttf',
  'fonts/stories/Parisienne-Regular.ttf',
  'fonts/stories/BarlowCondensed-Medium.ttf',
  'fonts/inter-v3.19/Inter-Medium.woff2',
  'fonts/inter-v3.19/Inter-Regular.woff2',
  'fonts/inter-v3.19/Inter-SemiBold.woff2',
  'fonts/inter-v3.19/Inter-BoldItalic.woff2',
  'fonts/inter-v3.19/Inter-Bold.woff2',
  'fonts/inter-v3.19/Inter-Italic.woff2',
  'fonts/inter-v3.19/Inter-SemiBoldItalic.woff2',
  'fonts/mono-special/MonoSpecial-Regular.woff2',
]);

// pathname to optional resource name
const OPTIONAL_ASSETS = new Map<string, string>([]);

if (!process.mas) {
  LOCAL_ASSETS.add('fonts/emoji.woff2');
  OPTIONAL_ASSETS.set('optional-fonts/emoji-large.woff2', 'emoji-font.woff2');
}

export class AssetService {
  readonly #resourceService: OptionalResourceService;

  private constructor(resourceService: OptionalResourceService) {
    this.#resourceService = resourceService;

    protocol.handle('asset', async req => {
      const url = new URL(req.url);

      try {
        return await this.#fetch(url.pathname);
      } catch (error) {
        log.error('protocol handler error', Errors.toLogFormat(error));
        return new Response('internal error', { status: 500 });
      }
    });
  }

  public static create(resourceService: OptionalResourceService): AssetService {
    return new AssetService(resourceService);
  }

  async #fetch(pathname: string): Promise<Response> {
    if (!pathname.startsWith('/')) {
      return new Response('invalid pathname', { status: 400 });
    }

    const path = pathname.slice(1);

    if (LOCAL_ASSETS.has(path)) {
      const content = await readFile(join(getAppRootDir(), ...path.split('/')));
      return new Response(content, {
        status: 200,
        headers: {
          'cache-control': 'public, max-age=2592000, immutable',
        },
      });
    }

    const optional = OPTIONAL_ASSETS.get(path);
    if (optional == null) {
      return new Response('asset not found', { status: 404 });
    }

    const asset = await this.#resourceService.getData(optional);
    if (!asset) {
      return new Response('optional asset not found', { status: 404 });
    }

    return new Response(asset, {
      status: 200,
      headers: {
        'cache-control': 'public, max-age=2592000, immutable',
      },
    });
  }
}
