/**
 * @mergeTarget
 * @module Src/Screens/Eco
 */
import {
  LisioCategory,
  LisioCategoryNames,
  LisioParameterNames,
  LisioProfileNames,
  LisioUser,
} from "@lisio/lisio-profils";
import { LisioScreen } from "../lisio-screen";
import {
  BooleanParameterRenderObject,
  StringParameterRenderObject,
  NumberParameterRenderObject,
  ComponentAndPosition,
  CategoryRenderObject,
  ProfileRenderObject,
  VisualCategoryNames,
  ScreenNames,
} from "../screen-types";
import { ListContainer } from "../../components/containers/list-container/list-container";
import { HomeScreen } from "../home/home-screen";
import { CustomText } from "../../components/custom-text/custom-text";
import { LisioComponent } from "@lisio/lisio-engine";
import { ElementsContainer } from "../../components/containers/elements-container/elements-container";
import { MoreScreen } from "../more/more-screen";
import { CustomLink } from "../../components/custom-link/custom-link";

type Resource = { size: number; loaded: boolean };

interface ResourceGroup {
  resources: { [key: string]: Resource };
  pageSize: number;
  totalSaved: number;
  totalLoaded: number;
}

type ResourceMap = {
  [key: string]: ResourceGroup;
};

/**
 * Class representing an eco screen component extending LisioScreen.\
 * It aims to represent an eco screen component.\
 * An eco screen component is basically a component to render all eco categories, profiles and parameters.\
 */
class EcoScreen extends LisioScreen {
  /**
   * Protected attribute to store category render objects
   * @source
   */
  protected _categoryRenderObjects: Map<
    VisualCategoryNames,
    CategoryRenderObject
  > = new Map<VisualCategoryNames, CategoryRenderObject>([
    [
      VisualCategoryNames.MORE,
      {
        buttonId: `${this.id}-more`,
        icon: {
          fileName: "footer-icons",
          iconName: "More",
        },
        titleId: "more-button",
        nextScreenName: MoreScreen.name,
        position: 10,
        isActive: false,
        activeSubObjects: new Set(),
        firstIconClasses: ["grey2"],
        iconsClasses: ["grey"],
        cssClasses: ["secondary", "footer-button"],
      },
    ],
  ]);

  /**
   * Protected attribute to store profile render objects
   * @source
   */
  protected _profileRenderObjects: Map<LisioProfileNames, ProfileRenderObject> =
    new Map<LisioProfileNames, ProfileRenderObject>([
      [
        LisioProfileNames.ECOLO,
        {
          buttonId: "ecological",
          titleId: "ecomode-disabled",
          activeTitleId: "ecomode-enabled",
          name: LisioProfileNames.ECOLO,
          value: false,
          position: 0,
          cssClasses: ["width-100", "btn-pill", "secondary", "space-between"],
          aria: {
            describedby: "infobox-ecolo",
          },
        } as ProfileRenderObject,
      ],
      [
        LisioProfileNames.LIGHT_ECOLO,
        {
          buttonId: "light-ecological",
          titleId: "light-ecological-subtitle",
          name: LisioProfileNames.LIGHT_ECOLO,
          position: 0,
          value: false,
          cssClasses: ["width-100", "btn-pill", "secondary", "space-between"],
          aria: {
            describedby: "infobox-light-ecological",
          },
          // infoBoxes: [
          //   // {
          //   //   textId: "infobox-light-ecological",
          //   //   cssClassesText: ["info-text"],
          //   // },
          // ],
        },
      ],
    ]);

  /**
   * Protected attribute to store parameter render objects
   * @source
   */
  protected _parameterRenderObjects: Map<
    LisioParameterNames,
    | BooleanParameterRenderObject
    | StringParameterRenderObject
    | NumberParameterRenderObject
  > = new Map<
    LisioParameterNames,
    | BooleanParameterRenderObject
    | StringParameterRenderObject
    | NumberParameterRenderObject
  >();

  private promise?: Promise<void>;

  /**
   * @async
   * Public method implementing abstract method render of LisioComponent
   * @returns Returns a promise containing the representation of a eco screen in HTML string
   * @source
   */
  public async render(): Promise<string> {
    if (this.promise != undefined) {
      await this.promise;
    }
    return `
    <section id="${this._id}" role="tabpanel">
      <children></children>
    </section>
    `;
  }

  /**
   * Constructor of class {@link EcoScreen | EcoScreen}
   * @param {LisioCategory} eco - eco category
   * @param {LisioUser | undefined} user - Current user
   * @source
   */
  constructor(eco: LisioCategory, isCompensation: boolean, user?: LisioUser) {
    if (__BUILD_TARGET__ === "extension") {
      eco.profileNames.splice(1, 1);
    }
    ScreenNames[EcoScreen.name] = "eco-screen";
    super(
      EcoScreen.name,
      EcoScreen.name,
      eco.profileNames.length > 1
        ? LisioCategoryNames.ECOLOGICAL
        : LisioCategoryNames.LIGHT_ECOLOGICAL,
      HomeScreen.name,
    );
    const profilesElements: ComponentAndPosition[] = this.initProfiles(
      eco.profileNames,
      [],
      user?.profiles,
    );
    const elementsTitleContainer: LisioComponent =
      this.createScreenTitle("eco-title");

    profilesElements.sort((a, b) => a.position - b.position);
    const firstElementsContainer: LisioComponent = new ListContainer(
      [profilesElements[0].component],
      undefined,
      ["column full", "secondary", "lines-h"],
    );

    const firstTextSection: LisioComponent = new ElementsContainer(
      [
        new CustomText(
          "p",
          eco.name === LisioCategoryNames.ECOLOGICAL
            ? "infobox-ecolo"
            : "infobox-light-ecological",
          false,
          ["info-text"],
          undefined,
          eco.name === LisioCategoryNames.ECOLOGICAL
            ? "infobox-ecolo"
            : "infobox-light-ecological",
        ),
      ],
      undefined,
      ["column", "full", "secondary", "infobox"],
    );
    if (profilesElements[1]) {
      const secondElementsContainer: LisioComponent = new ListContainer(
        [profilesElements[1].component],
        undefined,
        ["column full", "secondary", "lines-h"],
      );
      const secondTextSection: LisioComponent = new ElementsContainer(
        [
          new CustomText(
            "p",
            "infobox-light-ecological",
            false,
            ["info-text"],
            undefined,
            "infobox-light-ecological",
          ),
        ],
        undefined,
        ["column", "full", "secondary", "infobox"],
      );

      const contentAndFooterContainer: LisioComponent = new ListContainer(
        [
          firstElementsContainer,
          firstTextSection,
          secondElementsContainer,
          secondTextSection,
          ...(isCompensation ? this.createFooter(isCompensation) : []),
        ],
        undefined,
        ["column", "screen-ul", "width-100"],
      );
      this._children?.push(elementsTitleContainer, contentAndFooterContainer);
    } else {
      if (__BUILD_TARGET__ === "extension") {
        this.promise = new Promise(async (res) => {
          const datas = (await chrome.storage.local.get(["lisio-bytes-saved"]))[
            "lisio-bytes-saved"
          ];
          const extraP: LisioComponent[] = [];
          let csv = "page;url;bytes(Ko);loaded\n";
          const bytesInfos = (datas as ResourceMap) || {};
          const currentTab = await chrome.tabs.query({
            active: true,
            lastFocusedWindow: true,
          });
          const url = new URL(currentTab[0].url || "localhost");
          const page = url.origin + url.pathname;
          for (const page of Object.keys(bytesInfos)) {
            for (const url of Object.keys(bytesInfos[page].resources)) {
              csv += `${page};${url};${(
                bytesInfos[page].resources[url].size / 1000
              ).toFixed(2)};${bytesInfos[page].resources[url].loaded}\n`;
            }
            csv += `${page};html;${(bytesInfos[page].pageSize / 1000).toFixed(
              2,
            )};true\n`;
            csv += `${page};saved;${(
              bytesInfos[page].totalSaved / 1000
            ).toFixed(2)};true\n`;
            csv += `${page};loaded;${(
              bytesInfos[page].totalLoaded / 1000
            ).toFixed(2)};true\n`;
            csv += `${page};total;${(
              (bytesInfos[page].totalSaved + bytesInfos[page].totalLoaded) /
              1000
            ).toFixed(2)};true\n`;
          }
          const blob = new Blob([csv], { type: "octet/stream" });
          const name = `bytes-infos-${Date.now()}.csv`;
          const urlObj = window.URL.createObjectURL(blob);
          const bytesInfosDownload = new CustomLink(
            urlObj,
            [new CustomText("p", "Télécharger datas", true)],
            undefined,
            undefined,
            undefined,
            undefined,
            name,
          );
          if (page !== undefined && /^https?/.test(page)) {
            const numberOfUrls = Object.values(
              bytesInfos[page].resources,
            ).filter((datas) => !datas.loaded).length;

            const bytesSavedElement = new CustomText(
              "p",
              `Poids économisé : ${(bytesInfos[page].totalSaved / 1000).toFixed(
                2,
              )} Ko`,
              true,
            );
            const percentSavedElement = new CustomText(
              "p",
              `Pourcentage de réduction : ${(
                (bytesInfos[page].totalSaved /
                  (bytesInfos[page].totalSaved +
                    bytesInfos[page].totalLoaded)) *
                100
              ).toFixed(2)}%`,
              true,
            );
            const nSavedElement = new CustomText(
              "p",
              `Nombre de ressources bloquées : ${numberOfUrls}`,
              true,
            );

            extraP.push(
              bytesSavedElement,
              percentSavedElement,
              nSavedElement,
              bytesInfosDownload,
            );
          }

          const contentAndFooterContainer: LisioComponent = new ListContainer(
            [
              firstElementsContainer,
              firstTextSection,
              ...extraP,
              ...(isCompensation ? this.createFooter(isCompensation) : []),
            ],
            undefined,
            ["column test", "screen-ul", "width-100"],
          );

          this._children?.push(
            elementsTitleContainer,
            contentAndFooterContainer,
          );
          res();
        });
      } else {
        const contentAndFooterContainer: LisioComponent = new ListContainer(
          [
            firstElementsContainer,
            firstTextSection,
            ...(isCompensation ? this.createFooter(isCompensation) : []),
          ],
          undefined,
          ["column test", "screen-ul", "width-100"],
        );

        this._children?.push(elementsTitleContainer, contentAndFooterContainer);
      }
    }
  }
}

export { EcoScreen };
