/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

import { actionCreators as ac, actionTypes as at } from "common/Actions.mjs";
import { MIN_RICH_FAVICON_SIZE, TOP_SITES_SOURCE } from "./TopSitesConstants";
import { CollapsibleSection } from "content-src/components/CollapsibleSection/CollapsibleSection";
import { ComponentPerfTimer } from "content-src/components/ComponentPerfTimer/ComponentPerfTimer";
import { connect } from "react-redux";
import { ModalOverlayWrapper } from "content-src/components/ModalOverlay/ModalOverlay";
import React from "react";
import { SearchShortcutsForm } from "./SearchShortcutsForm";
import { TOP_SITES_MAX_SITES_PER_ROW } from "common/Reducers.sys.mjs";
import { TopSiteForm } from "./TopSiteForm";
import { TopSiteList } from "./TopSite";

function topSiteIconType(link) {
  if (link.customScreenshotURL) {
    return "custom_screenshot";
  }
  if (link.tippyTopIcon || link.faviconRef === "tippytop") {
    return "tippytop";
  }
  if (link.faviconSize >= MIN_RICH_FAVICON_SIZE) {
    return "rich_icon";
  }
  if (link.screenshot) {
    return "screenshot";
  }
  return "no_image";
}

/**
 * Iterates through TopSites and counts types of images.
 *
 * @param acc Accumulator for reducer.
 * @param topsite Entry in TopSites.
 */
function countTopSitesIconsTypes(topSites) {
  const countTopSitesTypes = (acc, link) => {
    acc[topSiteIconType(link)]++;
    return acc;
  };

  return topSites.reduce(countTopSitesTypes, {
    custom_screenshot: 0,
    screenshot: 0,
    tippytop: 0,
    rich_icon: 0,
    no_image: 0,
  });
}

export class _TopSites extends React.PureComponent {
  constructor(props) {
    super(props);
    this.onEditFormClose = this.onEditFormClose.bind(this);
    this.onSearchShortcutsFormClose =
      this.onSearchShortcutsFormClose.bind(this);
  }

  /**
   * Dispatch session statistics about the quality of TopSites icons and pinned count.
   */
  _dispatchTopSitesStats() {
    const topSites = this._getVisibleTopSites().filter(
      topSite => topSite !== null && topSite !== undefined
    );
    const topSitesIconsStats = countTopSitesIconsTypes(topSites);
    const topSitesPinned = topSites.filter(site => !!site.isPinned).length;
    const searchShortcuts = topSites.filter(
      site => !!site.searchTopSite
    ).length;
    // Dispatch telemetry event with the count of TopSites images types.
    this.props.dispatch(
      ac.AlsoToMain({
        type: at.SAVE_SESSION_PERF_DATA,
        data: {
          topsites_icon_stats: topSitesIconsStats,
          topsites_pinned: topSitesPinned,
          topsites_search_shortcuts: searchShortcuts,
        },
      })
    );
  }

  /**
   * Return the TopSites that are visible based on prefs and window width.
   */
  _getVisibleTopSites() {
    // We hide 2 sites per row when not in the wide layout.
    let sitesPerRow = TOP_SITES_MAX_SITES_PER_ROW;
    // $break-point-widest = 1072px (from _variables.scss)
    if (!globalThis.matchMedia(`(min-width: 1072px)`).matches) {
      sitesPerRow -= 2;
    }
    return this.props.TopSites.rows.slice(
      0,
      this.props.TopSitesRows * sitesPerRow
    );
  }

  componentDidUpdate() {
    this._dispatchTopSitesStats();
  }

  componentDidMount() {
    this._dispatchTopSitesStats();
  }

  onEditFormClose() {
    this.props.dispatch(
      ac.UserEvent({
        source: TOP_SITES_SOURCE,
        event: "TOP_SITES_EDIT_CLOSE",
      })
    );
    this.props.dispatch({ type: at.TOP_SITES_CANCEL_EDIT });
  }

  onSearchShortcutsFormClose() {
    this.props.dispatch(
      ac.UserEvent({
        source: TOP_SITES_SOURCE,
        event: "SEARCH_EDIT_CLOSE",
      })
    );
    this.props.dispatch({ type: at.TOP_SITES_CLOSE_SEARCH_SHORTCUTS_MODAL });
  }

  render() {
    const { props } = this;
    const { editForm, showSearchShortcutsForm } = props.TopSites;
    const extraMenuOptions = ["AddTopSite"];
    let visibleTopSites;
    const colors = props.Prefs.values["newNewtabExperience.colors"];

    // do not run this function when for startup cache
    if (!props.App.isForStartupCache.TopSites) {
      visibleTopSites = this._getVisibleTopSites()?.length;
    }

    if (props.Prefs.values["improvesearch.topSiteSearchShortcuts"]) {
      extraMenuOptions.push("AddSearchShortcut");
    }

    return (
      <ComponentPerfTimer
        id="topsites"
        initialized={props.TopSites.initialized}
        dispatch={props.dispatch}
      >
        <CollapsibleSection
          className="top-sites"
          id="topsites"
          title={props.title || { id: "newtab-section-header-topsites" }}
          hideTitle={true}
          extraMenuOptions={extraMenuOptions}
          showPrefName="feeds.topsites"
          eventSource={TOP_SITES_SOURCE}
          collapsed={false}
          isFixed={props.isFixed}
          isFirst={props.isFirst}
          isLast={props.isLast}
          dispatch={props.dispatch}
        >
          <TopSiteList
            TopSites={props.TopSites}
            TopSitesRows={props.TopSitesRows}
            dispatch={props.dispatch}
            topSiteIconType={topSiteIconType}
            colors={colors}
            visibleTopSites={visibleTopSites}
          />
          <div className="edit-topsites-wrapper">
            {editForm && (
              <div className="edit-topsites">
                <ModalOverlayWrapper
                  unstyled={true}
                  onClose={this.onEditFormClose}
                  innerClassName="modal"
                >
                  <TopSiteForm
                    site={props.TopSites.rows[editForm.index]}
                    onClose={this.onEditFormClose}
                    dispatch={this.props.dispatch}
                    {...editForm}
                  />
                </ModalOverlayWrapper>
              </div>
            )}
            {showSearchShortcutsForm && (
              <div className="edit-search-shortcuts">
                <ModalOverlayWrapper
                  unstyled={true}
                  onClose={this.onSearchShortcutsFormClose}
                  innerClassName="modal"
                >
                  <SearchShortcutsForm
                    TopSites={props.TopSites}
                    onClose={this.onSearchShortcutsFormClose}
                    dispatch={this.props.dispatch}
                  />
                </ModalOverlayWrapper>
              </div>
            )}
          </div>
        </CollapsibleSection>
      </ComponentPerfTimer>
    );
  }
}

export const TopSites = connect(state => ({
  App: state.App,
  TopSites: state.TopSites,
  Prefs: state.Prefs,
  TopSitesRows: state.Prefs.values.topSitesRows,
}))(_TopSites);
