import { CORE_TEMPLATES } from '../scripts/mappingTemplates.js';
import { TVA_CONFIG, updateSettings } from '../scripts/settings.js';
import { showMappingSelectDialog, showUserTemplateCreateDialog } from './dialogs.js';

export class Templates extends FormApplication {
  constructor({ mappings = null, callback = null } = {}) {
    super({}, {});
    this.mappings = mappings;
    this.callback = callback;
  }

  static get defaultOptions() {
    return mergeObject(super.defaultOptions, {
      id: 'token-variants-templates',
      classes: ['sheet'],
      template: 'modules/token-variants/templates/templates.html',
      resizable: false,
      minimizable: false,
      title: 'Mapping Templates',
      width: 500,
      height: 'auto',
    });
  }

  async getData(options) {
    const data = super.getData(options);

    if (!this.category) this.category = TVA_CONFIG.templateMappings?.length ? 'user' : 'core';
    if (this.category === 'user') {
      this.templates = TVA_CONFIG.templateMappings;
    } else if (this.category === 'core') {
      this.templates = CORE_TEMPLATES;
    } else {
      this.templates = await communityTemplates();
    }

    for (const template of this.templates) {
      template.hint = template.hint?.replace(/(\r\n|\n|\r)/gm, '<br>');
    }

    data.category = this.category;
    data.templates = this.templates;
    data.allowDelete = this.category === 'user';
    data.allowCreate = this.category === 'user';
    data.allowCopy = this.category === 'community' || this.category === 'core';

    return data;
  }

  /**
   * @param {JQuery} html
   */
  activateListeners(html) {
    super.activateListeners(html);

    // Position tooltip
    const appWindow = html.closest('#token-variants-templates');
    html.find('.template').on('mouseover', (event) => {
      const template = $(event.target).closest('.template');
      const pos = template.position();
      const tooltip = template.find('.tooltiptext');
      const windowPos = appWindow.position();
      tooltip.css('top', windowPos.top + pos.top).css('left', windowPos.left + pos.left);

      // Lazy load image
      const img = template.find('img');
      if (!img.attr('src')) img.attr('src', img.data('src'));
    });

    if (this.callback) {
      html.find('.template').on('click', async (event) => {
        const li = $(event.target).closest('.template');
        const id = li.data('id');
        const url = li.data('url');
        let mappings;
        let templateName;
        if (url) {
          const template = await getTemplateFromFileURL(url);
          if (template) mappings = template.mappings;
        } else if (id) {
          const template = this.templates.find((t) => t.id === id);
          if (template) {
            templateName = template.name;
            mappings = template.mappings;
          }
        }

        if (mappings) this.callback(templateName, mappings);
      });
    }

    html.find('.search').on('input', () => {
      const filter = html.find('.search').val().trim().toLowerCase();
      html.find('.template-list li').each(function () {
        const li = $(this);
        const description = li.find('.description').text().trim().toLowerCase();
        const name = li.data('name').trim().toLowerCase();
        const createdBy = li.data('creator').trim().toLowerCase();
        if (name.includes(filter) || description.includes(filter) || createdBy.includes(filter)) li.show();
        else li.hide();
      });
    });

    html.find('[name="category"]').on('change', (event) => {
      this.category = event.target.value;
      this.render(true);
    });

    html.find('.delete').on('click', async (event) => {
      event.preventDefault();
      event.stopPropagation();

      const id = $(event.target).closest('.template').data('id');
      if (id) {
        await updateSettings({
          templateMappings: TVA_CONFIG.templateMappings.filter((m) => m.id !== id),
        });
        this.render(true);
      }
    });

    html.find('.copy').on('click', async (event) => {
      event.preventDefault();
      event.stopPropagation();

      const id = $(event.target).closest('.template').data('id');
      if (id) {
        let template;
        if (this.category === 'core') {
          template = deepClone(CORE_TEMPLATES.find((t) => t.id === id));
        } else {
          const fileURL = $(event.target).closest('.template').data('url');
          if (fileURL) template = await getTemplateFromFileURL(fileURL);
        }

        if (template) {
          TVA_CONFIG.templateMappings.push(template);
          await updateSettings({
            templateMappings: TVA_CONFIG.templateMappings,
          });
          ui.notifications.info(`Template {${template.name}} copied to User templates.`);
          this.render(true);
        }
      }
    });

    html.find('.create').on('click', () => {
      showMappingSelectDialog(this.mappings, {
        title1: 'Create Template',
        callback: (selectedMappings) => {
          if (selectedMappings?.length) showUserTemplateCreateDialog(selectedMappings);
        },
      });
    });
  }

  _getHeaderButtons() {
    const buttons = super._getHeaderButtons();
    buttons.unshift({
      label: 'Upload Template',
      class: '.token-variants-submit-template',
      icon: 'fa-solid fa-cloud-arrow-up',
      onclick: () => {
        new TemplateSubmissionForm().render(true);
      },
    });
    return buttons;
  }

  /**
   * @param {Event} event
   * @param {Object} formData
   */
  async _updateObject(event, formData) {}
}

class TemplateSubmissionForm extends FormApplication {
  constructor() {
    super({}, {});
  }

  static apiKey = 'AIzaSyCJpwIkpjrG10jaHwcpllvSChxRPawcMXE';

  static get pk() {
    const k2 = 'AIzaSyCJpw';
    const k1 = 'IkpjrG10jaHwcpllv';
    const k3 = 'SChxRPawcMXE';
    return k2 + k1 + k3;
  }

  static get defaultOptions() {
    return mergeObject(super.defaultOptions, {
      id: 'token-variants-template-submission',
      classes: ['sheet'],
      template: 'modules/token-variants/templates/templateSubmission.html',
      resizable: true,
      minimizable: false,
      closeOnSubmit: false,
      title: 'Upload Template',
      width: 500,
      height: 'auto',
    });
  }

  async getData(options) {
    const data = super.getData(options);

    data.systemID = game.system.id;
    data.systemTitle = game.system.title;
    data.templates = TVA_CONFIG.templateMappings;

    data.modules = game.modules
      .filter((m) => m.active)
      .map((m) => {
        return { id: m.name, name: m.title };
      });

    return data;
  }

  /**
   * @param {Event} event
   * @param {Object} formData
   */
  async _updateObject(event, formData) {
    if (!formData.template) return;
    let template = TVA_CONFIG.templateMappings.find((t) => t.id === formData.template);
    if (!template) return;

    const name = formData.name.trim() || template.name;
    const hint = formData.hint.trim() || template.hint?.trim();
    const createdBy = formData.createdBy.trim();
    const system = formData.system;

    if (!(formData.modules instanceof Array)) formData.modules = [formData.modules];
    const modules = formData.modules.filter(Boolean).map((id) => {
      return { id, name: game.modules.get(id).title };
    });

    const id = randomID();
    const img = formData.img.trim();

    const result = await submitTemplate({
      id,
      name,
      hint,
      img,
      createdBy,
      system,
      modules,
      mappings: template.mappings,
    });
    if (result) this.close();
  }
}

function _setStringField(template, fields, field) {
  if (template[field] && template[field] !== '') {
    fields[field] = { stringValue: template[field] };
  }
}

async function submitTemplate(template) {
  const fields = {};
  ['name', 'hint', 'img', 'id', 'createdBy', 'system'].forEach((field) => _setStringField(template, fields, field));
  fields.modules = { stringValue: template.modules.length ? JSON.stringify(template.modules) : '' };
  fields.mappings = { stringValue: JSON.stringify(template.mappings) };
  fields.createTime = { integerValue: new Date().getTime() };
  fields.approved = { booleanValue: false };

  const response = await fetch(
    `https://firestore.googleapis.com/v1/projects/tva---templates/databases/(default)/documents/templates?key=${TemplateSubmissionForm.pk}`,
    {
      method: 'POST',
      body: JSON.stringify({
        fields: fields,
      }),
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
    }
  );

  if (response.ok && response.status === 200) {
    ui.notifications.info('Template submission completed.');
    return true;
  } else {
    ui.notifications.warn('Template submission failed.');
    return false;
  }
}

const SEARCH_QUERY = {
  structuredQuery: {
    select: {
      fields: [
        {
          fieldPath: 'id',
        },
        {
          fieldPath: 'name',
        },
        {
          fieldPath: 'hint',
        },
        {
          fieldPath: 'createdBy',
        },
        {
          fieldPath: 'img',
        },
        {
          fieldPath: 'system',
        },
        {
          fieldPath: 'modules',
        },
      ],
    },
    where: {
      fieldFilter: {
        field: {
          fieldPath: 'approved',
        },
        op: 'EQUAL',
        value: {
          booleanValue: true,
        },
      },
    },
    from: [{ collectionId: 'templates' }],
    orderBy: [
      {
        field: {
          fieldPath: 'createTime',
        },
      },
    ],
    offset: 0,
    limit: 50,
  },
};

async function communityTemplates(search = null) {
  const response = await fetch(
    `https://firestore.googleapis.com/v1/projects/tva---templates/databases/(default)/documents:runQuery?key=${TemplateSubmissionForm.pk}`,
    {
      method: 'POST',
      body: JSON.stringify(SEARCH_QUERY),
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
    }
  );

  const templates = [];
  if (response.ok && response.status === 200) {
    const documents = await response.json();

    for (let doc of documents) {
      if ('document' in doc) templates.push(_docToTemplate(doc.document));
    }
  } else {
    ui.notifications.warn('Failed to retrieve Community templates.');
  }
  return templates;
}

function _docToTemplate(doc) {
  const template = {};
  ['id', 'name', 'mappings', 'createdBy', 'img', 'hint', 'system', 'modules'].forEach((f) => {
    template[f] = doc.fields[f]?.stringValue || '';
  });
  if (template.mappings) template.mappings = JSON.parse(template.mappings);
  else template.fileURL = doc.name;

  if (template.modules) template.modules = JSON.parse(template.modules);

  if (!template.createdBy) template.createdBy = 'Anonymous';
  return template;
}

async function getTemplateFromFileURL(fileURL) {
  const response = await fetch(`https://firestore.googleapis.com/v1/${fileURL}?key=${TemplateSubmissionForm.pk}`, {
    method: 'GET',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
  });

  if (response.ok && response.status === 200) {
    const doc = await response.json();
    return _docToTemplate(doc);
  }
  return null;
}
