import { createTranslationFunc } from './utils';
import { calcLoyalty } from './lib/tw';
import { Cache } from './lib/cache';
import {
  TWHelpClient,
  Ennoblement,
  ServerConfig,
  AxiosHttpRequestWithTimeout,
} from './lib/twhelp';
import { DialogTable } from './common/dialog-table';

const t = createTranslationFunc({
  pl_PL: {
    'Show ennoblements': 'Pokaż przejęcia',
    'Date/time': 'Data/czas',
    Village: 'Wioska',
    'Old owner': 'Stary właściciel',
    'New owner': 'Nowy właściciel',
    Points: 'Punkty',
    Barbarian: 'Barbarzyńska',
    'Ennobled at': 'Ostatnio przejęta',
    Unknown: 'Nieznany',
    Loyalty: 'Poparcie',
    Never: 'Nigdy',
  },
});

class TWHelpConnector {
  private static SERVER_CONFIG_CACHE_KEY =
    'extended_village_profile_server_config_v2';

  private cache = new Cache(localStorage);

  private client: TWHelpClient;

  constructor(
    readonly baseUrl: string,
    private readonly version: string,
    private readonly server: string,
    private readonly id: number
  ) {
    this.client = new TWHelpClient(
      {
        BASE: baseUrl,
      },
      AxiosHttpRequestWithTimeout
    );
  }

  serverConfig() {
    return this.cache.load(
      TWHelpConnector.SERVER_CONFIG_CACHE_KEY,
      3600,
      async () => {
        return (
          await this.client.servers.getServerConfig({
            versionCode: this.version,
            serverKey: this.server,
          })
        ).data;
      }
    );
  }

  async latestEnnoblement() {
    const ennoblements = await this.client.ennoblements.listVillageEnnoblements(
      {
        versionCode: this.version,
        serverKey: this.server,
        villageId: this.id,
        limit: 1,
        sort: ['createdAt:DESC'],
      }
    );
    return ennoblements.data.length > 0 ? ennoblements.data[0] : null;
  }

  villageEnnoblements(cursor: string | undefined, limit: number) {
    return this.client.ennoblements.listVillageEnnoblements({
      cursor,
      versionCode: this.version,
      serverKey: this.server,
      villageId: this.id,
      limit: limit,
      sort: ['createdAt:DESC'],
    });
  }
}

enum DialogId {
  ENNOBLEMENTS = 'extended_village_profile_ennoblements',
}

class UI {
  constructor(
    private readonly config: ServerConfig,
    private readonly ennoblement: Ennoblement | null,
    private readonly connector: TWHelpConnector
  ) {}

  render() {
    this.renderAdditionalInfo();
    this.renderActions();
  }

  private renderAdditionalInfo() {
    const tbody = document.querySelector('#embedmap_village')?.closest('tbody');
    if (!(tbody instanceof HTMLTableSectionElement)) {
      return;
    }

    tbody.insertAdjacentHTML(
      'beforeend',
      `
    <tr>
        <td>${t('Ennobled at')}:</td>
        <td>${
          this.ennoblement
            ? new Date(this.ennoblement.createdAt).toLocaleString()
            : t('Never')
        }</td>
    </tr>
    <tr>
        <td>${t('Loyalty')}:</td>
        <td>${calcLoyalty(
          this.ennoblement?.createdAt ?? 0,
          this.config.speed
        )}</td>
    </tr>
  `
    );
  }

  private renderActions() {
    const tbody = document
      .querySelector('#content_value a[href*="twstats"]')
      ?.closest('tbody');
    if (!(tbody instanceof HTMLTableSectionElement)) {
      return;
    }

    [
      {
        name: t('Show ennoblements'),
        handler: this.showEnnoblements.bind(this),
      },
    ].forEach(({ name, handler }) => {
      const tr = document.createElement('tr');
      const td = document.createElement('td');
      td.colSpan = 2;
      const a = document.createElement('a');
      a.innerText = name;
      a.href = '#';
      a.addEventListener('click', handler);
      td.appendChild(a);
      tr.appendChild(td);
      tbody.appendChild(tr);
    });
  }

  private async showEnnoblements(e: Event) {
    e.preventDefault();

    await new DialogTable<Ennoblement>(
      DialogId.ENNOBLEMENTS,
      [
        {
          header: t('Village'),
          accessor: (e) =>
            `<a href="${e.village.profileUrl}">${e.village.fullName}</a>`,
        },
        {
          header: t('Points'),
          accessor: (e) => e.points.toLocaleString(),
        },
        {
          header: t('Old owner'),
          accessor: ({ village: { player } }) => {
            if (!player) {
              return t('Barbarian');
            }
            return `<a href="${player.profileUrl}">${player.name}</a>${
              player.tribe
                ? ` (<a href="${player.tribe.profileUrl}">${player.tribe.tag}</a>)`
                : ''
            }`;
          },
        },
        {
          header: t('New owner'),
          accessor: ({ newOwner }) => {
            if (!newOwner) {
              return t('Unknown');
            }
            return `<a href="${newOwner.profileUrl}">${newOwner.name}</a>${
              newOwner.tribe
                ? ` (<a href="${newOwner.tribe.profileUrl}">${newOwner.tribe.tag}</a>)`
                : ''
            }`;
          },
        },
        {
          header: t('Date/time'),
          accessor: (e) => new Date(e.createdAt).toLocaleString(),
        },
      ],
      30,
      async (cursor, limit) => {
        return this.connector.villageEnnoblements(cursor, limit);
      }
    ).render();
  }
}

class ExtendedVillageProfile {
  connector: TWHelpConnector;
  constructor(apiBaseUrl: string) {
    this.connector = new TWHelpConnector(
      apiBaseUrl,
      window.game_data.market,
      window.game_data.world,
      this.getVillageId()
    );
  }

  async run() {
    const [config, ennoblement] = await Promise.all([
      this.connector.serverConfig(),
      this.connector.latestEnnoblement(),
    ]);

    new UI(config, ennoblement, this.connector).render();
  }

  private getVillageId() {
    const str = new URLSearchParams(window.location.search).get('id');
    if (!str) {
      return 0;
    }
    return parseInt(str);
  }
}

(async () => {
  if (
    window.game_data.screen !== 'info_village' ||
    window.game_data.mode !== null
  ) {
    return;
  }

  await new ExtendedVillageProfile(process.env.TWHELP_API_BASE_URL ?? '')
    .run()
    .catch((err) => {
      console.log(err);
    });
})();
