import {
  MovieMetadata,
  MusicAlbumMetadata,
  MusicArtistMetadata,
  OtherVideoMetadata,
  ShowMetadata,
} from '@tunarr/types';
import { injectable } from 'inversify';
import { isNull } from 'lodash-es';
import { basename, extname } from 'node:path';
import { v4 } from 'uuid';
import { Nullable } from '../../types/util.ts';
import { parseIntOrNull } from '../../util/index.ts';
import { titleToSortTitle } from '../../util/programs.ts';

// TODO: Maybe make this customizable
const MovieNameRegex = /^(.*?)[.(](\d{4})[.)].*\.\w+$/;
const AlbumNameRegex = /^(.+?)(?:\s+\((\d{4})\))?$/;

@injectable()
export class FallbackMetadataService {
  constructor() {}

  getShowFallbackMetadata(showFolderPath: string): ShowMetadata {
    const title = basename(showFolderPath);
    const metadata: ShowMetadata = {
      actors: [],
      genres: [],
      identifiers: [],
      plot: null,
      rating: null,
      releaseDate: null,
      releaseDateString: null,
      title,
      sortTitle: titleToSortTitle(title),
      sourceType: 'local',
      studios: [],
      summary: null,
      tagline: null,
      tags: [],
      type: 'show',
      uuid: v4(),
      year: null,
      artwork: [],
    };
    return metadata;
  }

  getMovieFallbackMetadata(movieFilePath: string): MovieMetadata {
    const title = basename(movieFilePath, extname(movieFilePath));
    const metadata: MovieMetadata = {
      identifiers: [],
      originalTitle: null,
      releaseDate: null,
      releaseDateString: null,
      sortTitle: titleToSortTitle(title),
      sourceType: 'local',
      summary: null,
      title,
      tags: [],
      type: 'movie',
      uuid: v4(),
      year: null,
      plot: null,
      rating: null,
      tagline: null,
      artwork: [],
      state: 'ok',
    };

    const filename = basename(movieFilePath);
    const matches = filename.match(MovieNameRegex);
    if (!matches || matches.length === 0) {
      return metadata;
    }

    metadata.title = matches[1]?.trim() ?? title;
    metadata.sortTitle = metadata.title;

    const maybeYear = parseIntOrNull(matches[2] ?? '');

    if (!isNull(maybeYear)) {
      metadata.year = maybeYear;
    }

    const metadataExtractorRegex = /[({[](.*?)[)}\]]/g;

    for (const match of filename.matchAll(metadataExtractorRegex)) {
      const service = match?.[1]?.toLowerCase().trim().split('-', 2) ?? '';
      if (['imdb', 'tmdb'].includes(service?.[0] ?? '')) {
        if (service.length === 2) {
          metadata.identifiers.push({
            id: service[1]!.trim(),
            type: service[0] === 'imdb' ? 'imdb' : 'tmdb',
          });
        }
      }
    }

    return metadata;
  }

  getOtherVideoFallbackMetadata(filePath: string): OtherVideoMetadata {
    const title = basename(filePath, extname(filePath));
    return {
      identifiers: [],
      originalTitle: null,
      releaseDate: null,
      releaseDateString: null,
      sortTitle: titleToSortTitle(title),
      sourceType: 'local',
      title,
      tags: [],
      type: 'other_video',
      uuid: v4(),
      year: null,
      artwork: [],
      state: 'ok',
    };
  }

  getArtistFallbackMetadata(artistDirectory: string): MusicArtistMetadata {
    const title = basename(artistDirectory);
    const metadata: MusicArtistMetadata = {
      genres: [],
      identifiers: [],
      plot: null,
      title,
      sortTitle: titleToSortTitle(title),
      sourceType: 'local',
      summary: null,
      tagline: null,
      tags: [],
      type: 'artist',
      uuid: v4(),
      artwork: [],
    };
    return metadata;
  }

  getAlbumFallbackMetadata(albumDirectory: string): MusicAlbumMetadata {
    const title = basename(albumDirectory);

    const matches = title.match(AlbumNameRegex);
    let year: Nullable<number> = null;
    if (matches && matches[2]) {
      year = parseIntOrNull(matches[2]);
    }

    const metadata: MusicAlbumMetadata = {
      genres: [],
      identifiers: [],
      plot: null,
      title,
      sortTitle: titleToSortTitle(title),
      sourceType: 'local',
      summary: null,
      tagline: null,
      tags: [],
      type: 'album',
      uuid: v4(),
      artwork: [],
      year,
      releaseDate: null,
      releaseDateString: null,
    };
    return metadata;
  }
}
