/**
 * content for invoices
 */

import {
  DeesElement,
  property,
  html,
  customElement,
  type TemplateResult,
  css,
  render,
  domtools,
} from "@design.estate/dees-element";
import * as plugins from "../plugins.js";

import { dedocumentSharedStyle } from "../style.js";
import type { TranslationKey } from "ts_shared/translation.js";

declare global {
  interface HTMLElementTagNameMap {
    "dedocument-contentinvoice": DeContentInvoice;
  }
}

@customElement("dedocument-contentinvoice")
export class DeContentInvoice extends DeesElement {
  public static demo = () => html`
    <style>
      .demoContainer {
        background: white;
        padding: 50px;
      }
    </style>
    <div class="demoContainer">
      <dedocument-contentinvoice></dedocument-contentinvoice>
    </div>
  `;

  @property({
    type: Object,
    reflect: true,
  })
  public letterData: plugins.tsclass.finance.TInvoice;

  @property({
    type: Object,
    reflect: true,
  })
  public documentSettings: plugins.shared.interfaces.IDocumentSettings;

  constructor() {
    super();
    domtools.DomTools.setupDomTools();
  }

  public static styles = [
    domtools.elementBasic.staticStyles,
    dedocumentSharedStyle,
    css`
      .trimmedContent {
        display: none;
      }

      .grid {
        display: grid;
        grid-template-columns: 40px auto 50px 50px 100px 50px 100px;
      }

      .topLine {
        margin-top: 5px;
        background: #e7e7e7;
        font-weight: bold;
      }

      .lineItem {
        font-size: 12px;
        padding: 5px;
        border-right: 1px dashed #ccc;
        white-space: nowrap;
      }

      .lineItem:last-child {
        border-right: none;
      }

      .value.rightAlign,
      .lineItem.rightAlign {
        text-align: right;
      }

      .invoiceLine {
        background: #ffffff00;
        border-bottom: 1px dotted #ccc;
      }

      .invoiceLine.highlighted {
        transition: background 0.2s;
        background: #ffc18f;
        border: 1px solid #ff9d4d;
        box-sizing: content-box;
      }

      .sums {
        margin-top: 5px;
        font-size: 12px;
        padding-left: 50%;
      }

      .sums .sumline {
        margin-top: 3px;
        display: grid;
        grid-template-columns: auto 100px;
      }

      .sums .sumline .label {
        padding: 2px 5px;
        border-right: 1px solid #ccc;
        text-align: right;
        font-weight: bold;
      }

      .sums .sumline .value {
        padding: 2px 5px;
      }

      .sums .sumline .value--total {
        font-weight: bold;
      }

      .divider {
        margin-top: 8px;
        border-top: 1px dotted #ccc;
      }

      .taxNote {
        font-size: 12px;
        padding: 4px;
        background: #eeeeeb;
        text-align: center;
      }

      .infoBox {
        margin-top: 22px;
        line-height: 1.4em;
      }

      .infoBox .label {
        padding-bottom: 2px;
        font-weight: bold;
      }
    `,
  ];

  public render(): TemplateResult {
    return html`
      <div class="trimmedContent"></div>
      <div class="repeatedContent"></div>
      <div class="currentContent"></div>
    `;
  }

  protected formatPrice(
    value: number,
    currency = "EUR",
    lang = "de-DE"
  ): string {
    return new Intl.NumberFormat(lang, {
      style: "currency",
      currency,
    }).format(value);
  }

  public getTotalNet = (): number => {
    let totalNet = 0;

    if (!this.letterData) {
      return totalNet;
    }

    for (const item of this.letterData.items) {
      totalNet += item.unitNetPrice * item.unitQuantity;
    }
    return totalNet;
  };

  public getTotalGross = (): number => {
    let totalVat = 0;

    if (!this.letterData) {
      return totalVat;
    }

    for (const taxgroup of this.getVatGroups()) {
      totalVat += taxgroup.vatAmountSum;
    }
    return this.getTotalNet() + totalVat;
  };

  public getVatGroups = () => {
    const vatGroups: {
      vatPercentage: number;
      items: plugins.tsclass.finance.TInvoice["items"];
      vatAmountSum: number;
    }[] = [];

    if (!this.letterData) {
      return vatGroups;
    }

    const taxAmounts: number[] = [];
    for (const item of this.letterData.items) {
      taxAmounts.includes(item.vatPercentage)
        ? null
        : taxAmounts.push(item.vatPercentage);
    }

    for (const taxAmount of taxAmounts) {
      const matchingItems = this.letterData.items.filter(
        (itemArg) => itemArg.vatPercentage === taxAmount
      );
      let sum = 0;
      for (const matchingItem of matchingItems) {
        sum +=
          matchingItem.unitNetPrice *
          matchingItem.unitQuantity *
          (taxAmount / 100);
      }
      vatGroups.push({
        items: matchingItems,
        vatPercentage: taxAmount,
        vatAmountSum: Math.round(sum * 100) / 100,
      });
    }
    return vatGroups.sort((a, b) => b.vatPercentage - a.vatPercentage);
  };

  public async getContentNodes() {
    await this.elementDomReady;
    return {
      currentContent: this.shadowRoot.querySelector(
        ".currentContent"
      ) as HTMLElement,
      trimmedContent: this.shadowRoot.querySelector(
        ".trimmedContent"
      ) as HTMLElement,
      repeatedContent: this.shadowRoot.querySelector(
        ".repeatedContent"
      ) as HTMLElement,
    };
  }

  public async getContentLength() {
    await this.elementDomReady;
    return (await this.getContentNodes()).currentContent.children.length;
  }

  public async trimEndByOne() {
    await this.elementDomReady;
    this.shadowRoot
      .querySelector(".trimmedContent")
      .append(
        (await this.getContentNodes()).currentContent.children.item(
          (await this.getContentNodes()).currentContent.children.length - 1
        )
      );
  }

  public async trimStartToOffset(contentOffsetArg: number) {
    await this.elementDomReady;
    const beginningLength = (await this.getContentNodes()).currentContent
      .children.length;
    while (
      (await this.getContentNodes()).currentContent.children.length !==
      beginningLength - contentOffsetArg
    ) {
      (await this.getContentNodes()).trimmedContent.append(
        (await this.getContentNodes()).currentContent.children.item(0)
      );
    }
    if (
      (await this.getContentNodes()).currentContent.children
        .item(0)
        .classList.contains("needsDataHeader")
    ) {
      const trimmedContent = (await this.getContentNodes()).trimmedContent;
      let startPoint = trimmedContent.children.length;
      while (startPoint > 0) {
        const element = trimmedContent.children.item(startPoint - 1);
        if (element.classList.contains("dataHeader")) {
          (await this.getContentNodes()).repeatedContent.append(element);
          break;
        }
        startPoint--;
      }
    }
  }

  public translateKey(key: TranslationKey): string {
    return plugins.shared.translation.translate(
      this.documentSettings.languageCode,
      key
    );
  }

  public async firstUpdated(
    _changedProperties: Map<string | number | symbol, unknown>
  ) {
    super.firstUpdated(_changedProperties);
    this.attachInvoiceDom();
  }

  private renderPaymentTerms(): TemplateResult {
    return html`<div class="infoBox">
      <div>
        <div>
          <div class="label">
            ${this.translateKey("invoice@@payment.terms")}
          </div>
          <span>
            ${this.translateKey("invoice@@payment.terms.direct")}
            ${new Intl.DateTimeFormat(this.documentSettings.languageCode, {
              dateStyle: this.documentSettings.dateStyle,
            }).format(
              new Date(this.letterData.date).setDate(
                new Date(this.letterData.date).getDate() +
                  this.letterData?.dueInDays
              )
            )}
          </span>
        </div>
      </div>
    </div>`;
  }

  private renderPaymentInfo(): TemplateResult {
    const bic = this.letterData?.from.sepaConnection.bic;
    const name = this.letterData?.from.name;
    const iban = this.letterData?.from.sepaConnection.iban;
    const currency = this.letterData?.currency;
    const totalGross = this.getTotalGross();
    const reference = this.letterData?.id;

    return html`<div class="infoBox">
      <div>
        <div>
          <div class="label">${this.translateKey("invoice@@payment.qr")}</div>
          <span> ${this.translateKey("invoice@@payment.qr.description")} </span>
        </div>
        <dedocument-paymentcode
          bic="${bic}"
          name="${name}"
          iban="${iban}"
          currency="${currency}"
          totalGross="${totalGross}"
          reference="${reference}"
        />
      </div>
    </div>`;
  }

  private renderReferencedContract(): TemplateResult {
    return null;
    // return this.documentSettings.enableInvoiceContractRefSection &&
    //   this.invoiceData?.content?.contractData?.contractDate
    //   ? html`
    //       <div class="infoBox">
    //         <div class="label">
    //           ${this.translateKey("invoice@@referencedContract")}
    //         </div>
    //         ${this.translateKey("invoice@@referencedContract.text")}
    //         ${new Intl.DateTimeFormat(this.documentSettings.languageCode, {
    //           dateStyle: this.documentSettings.dateStyle,
    //         }).format(
    //           new Date(this.invoiceData?.content.contractData.contractDate)
    //         )}.
    //       </div>
    //     `
    //   : null;
  }

  public async attachInvoiceDom() {
    const contentNodes = await this.getContentNodes();
    render(
      html`
        <div>${this.translateKey("invoice@@introStatement")}</div>
        <div class="grid topLine dataHeader">
          <div class="lineItem rightAlign">
            ${this.translateKey("invoice@@item.position")}
          </div>
          <div class="lineItem">
            ${this.translateKey("invoice@@description")}
          </div>
          <div class="lineItem rightAlign">
            ${this.translateKey("invoice@@quantity")}
          </div>
          <div class="lineItem">${this.translateKey("invoice@@unit.type")}</div>
          <div class="lineItem rightAlign">
            ${this.translateKey("invoice@@price.unit.net")}
          </div>
          <div class="lineItem rightAlign">
            ${this.translateKey("invoice@@vat.short")}
          </div>
          <div class="lineItem rightAlign">
            ${this.translateKey("invoice@@price.total.net")}
          </div>
        </div>
        ${this.letterData?.items?.map(
          (invoiceItem, index) => html`
            <div class="grid needsDataHeader">
              <div class="lineItem rightAlign">${index + 1}</div>
              <div class="lineItem">${invoiceItem.name}</div>
              <div class="lineItem rightAlign">${invoiceItem.unitQuantity}</div>
              <div class="lineItem">${invoiceItem.unitType}</div>
              <div class="lineItem rightAlign">
                ${this.formatPrice(invoiceItem.unitNetPrice)}
              </div>
              <div class="lineItem rightAlign">
                ${invoiceItem.vatPercentage}%
              </div>
              <div class="lineItem rightAlign">
                ${this.formatPrice(
                  invoiceItem.unitQuantity * invoiceItem.unitNetPrice
                )}
              </div>
            </div>
          `
        )}
        <div class="sums">
          <div class="sumline">
            <div class="label">
              ${this.translateKey("invoice@@sum.total.net")}
            </div>
            <div class="value value--total rightAlign">
              ${this.formatPrice(this.getTotalNet())}
            </div>
          </div>
          ${this.getVatGroups().map((vatGroupArg) => {
            let itemNumbers = vatGroupArg.items
              .map((item) => this.letterData.items.indexOf(item) + 1)
              .join(", ");
            return html`
              <div class="sumline">
                <div class="label">
                  ${this.translateKey("vat.short")}
                  ${vatGroupArg.vatPercentage}%
                  ${this.documentSettings.vatGroupPositions
                    ? html`
                        <br /><span style="font-weight: normal"
                          >(${this.translateKey("invoice@@vat.position")}:
                          ${itemNumbers})</span
                        >
                      `
                    : html``}
                </div>
                <div class="value rightAlign">
                  ${this.formatPrice(vatGroupArg.vatAmountSum)}
                </div>
              </div>
            `;
          })}
          <div class="sumline">
            <div class="label">${this.translateKey("invoice@@totalGross")}</div>
            <div class="value value--total rightAlign">
              ${this.formatPrice(this.getTotalGross())}
            </div>
          </div>
        </div>
        <div class="divider"></div>

        ${this.letterData?.reverseCharge
          ? html`<div class="taxNote">
              ${this.translateKey("invoice@@vat.reverseCharge.note")}
            </div>`
          : ``}

        <!-- REFERENCED CONTRACT -->
        ${this.renderReferencedContract()}

        <!-- PAYMENT TERMS -->
        ${this.renderPaymentTerms()}

        <!-- PAYMENT INFO -->
        ${this.renderPaymentInfo()}
      `,
      contentNodes.currentContent
    );
  }
}