/* eslint-disable max-len */

import { Tags } from '@/tag';
import { parseCommaSeparatedKeyString } from '@/utility/key';
import { z } from 'zod';

export type AiAutoGeneratedField =
  'title' |
  'caption' |
  'tags' |
  'semantic'

export const AI_AUTO_GENERATED_FIELDS_ALL: AiAutoGeneratedField[] = [
  'title',
  'caption',
  'tags',
  'semantic',
];

export const AI_AUTO_GENERATED_FIELDS_DEFAULT: AiAutoGeneratedField[] = [
  'title',
  'tags',
  'semantic',
];

export const parseAiAutoGeneratedFieldsString = (
  string?: string,
) =>
  parseCommaSeparatedKeyString({
    string,
    acceptedKeys: AI_AUTO_GENERATED_FIELDS_ALL,
    defaultKeys: AI_AUTO_GENERATED_FIELDS_DEFAULT,
  });

export const getAiTextFieldsToGenerate = (
  textFieldsToGenerate: AiAutoGeneratedField[],
  excludeTitle?: boolean,
  excludeCaption?: boolean,
  excludeTags?: boolean,
  excludeSemantic?: boolean,
): AiAutoGeneratedField[] => {
  return textFieldsToGenerate.filter(field =>
    !(excludeTitle && field === 'title') &&
    !(excludeCaption && field === 'caption') &&
    !(excludeTags && field === 'tags') &&
    !(excludeSemantic && field === 'semantic'),
  );
};

export type AiImageQuery =
  'title' |
  'caption' |
  'title-and-caption' |
  'tags' |
  'semantic';

export const getAiImageQuery = (
  query: AiImageQuery,
  existingTitle?: string,
  existingTags: Tags = [],
): string => {
  switch (query) {  
    case 'title': return 'Write a compelling title for this image in 3 words or less.';
    case 'caption': return existingTitle
      ? `Write a pithy caption for this image in 6 words or less and no punctuation that complements the existing title: "${existingTitle}."`
      : 'Write a pithy caption for this image in 6 words or less and no punctuation.';
    case 'title-and-caption': return 'Write a compelling title and pithy caption of 8 words or less for this image, using the format Title: "title" Caption: "caption."';
    case 'tags':
      const tagQuery = 'Describe this image in 1-2 comma-separated unique keywords, with no adjective or adverbs. Avoid using general terms like "nature," "travel," "architecture," or "sky." Use terms that are highly specific to the image and not redundant.';
      const tags = existingTags.map(({ tag }) => tag).join(', ');
      return tags
        ? `${tagQuery}. Consider using some of these existing tags, but only if they are relevant: ${tags}.`
        : tagQuery;
    case 'semantic': return 'Describe this image succinctly without initial text like "This image shows" or "This is a picture of."';
  }
};

const getAiImageQueryForField = (
  field: AiAutoGeneratedField,
  existingTitle?: string,
  existingTags?: Tags,
) => {
  switch(field) {
    case 'title': return `TITLE: ${getAiImageQuery('title', existingTitle, existingTags)}`;
    case 'caption': return `CAPTION: ${getAiImageQuery('caption', existingTitle, existingTags)}`;
    case 'tags': return `TAGS: ${getAiImageQuery('tags', existingTitle, existingTags)}`;
    case 'semantic': return `SEMANTIC: ${getAiImageQuery('semantic', existingTitle, existingTags)}`;
  }
};

export const getAiImageQuerySchema = (
  fields: AiAutoGeneratedField[],
  existingTitle?: string,
  existingTags?: Tags,
) => {
  const queryLines = [
    'Generate a set of meta content for the attached image:\n',
  ];

  fields.forEach(field => {
    queryLines.push(getAiImageQueryForField(field, existingTitle, existingTags));
  });

  const query = queryLines.join('\n');

  let schema = z.object();
  
  if (fields.includes('title')) {
    schema = schema.extend({ title: z.string() }); }
  if (fields.includes('caption')) {
    schema = schema.extend({ caption: z.string() }); }
  if (fields.includes('tags')) {
    schema = schema.extend({ tags: z.string() }); }
  if (fields.includes('semantic')) {
    schema = schema.extend({ semantic: z.string() }); }

  return {
    query,
    schema,
  };
};

export const parseTitleAndCaption = (text: string) => {
  const matches = text.includes('Title')
    ? text.match(/^[`'"]*Title: ["']*(.*?)["']*[ ]*Caption: ["']*(.*?)\.*["']*[`'"]*$/)
    : text.match(/^(.*?): (.*?)$/);

  return {
    title: matches?.[1] ?? '',
    caption: matches?.[2] ?? '',
  };
};

export const cleanUpAiTextResponse = (text: string) =>
  text
    .replaceAll('\n', ' ')
    .replaceAll('"', '')
    .replaceAll('**', '')
    .replaceAll('`', '')
    .replace(/\.$/, '');
