import { ReactElement, useState, useMemo } from 'react';

import { useAppDispatch, useAppSelector } from '../../store/hooks';
import { clearSelectionAndSelectMulti, selectSimilarUrls, selectSelectedUrls } from '../../store/uiSlice';
import { selectWindowsSortedExcept } from '../../store/selectors';
import { selectTabs, selectDuplicateUrls, dedupAll } from '../../store/windowsSlice';

import WindowTabList from './WindowTabList';
import { useLiveQuery } from 'dexie-react-hooks';
import { getTabvanaWindowId } from '../../db/prefs';
import FlexViewHeader from '../flexView/FlexViewHeader';
import Inspector from '../inspector/Inspector';
import { RootState } from '../../store/rootState';
import SplitPane from 'react-split-pane';
import { Page, PageFilter, PageSortOrder, fetchPagesByNormalizedUrls, fetchPages } from '../../db/pages';
import { sortBy } from 'lodash';
import { pageSortOrderMap, filterPage } from '../sort';
import PageRow from '../flexView/pagelists/pagerow/PageRow';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faClone } from '@fortawesome/free-solid-svg-icons';
import IconButton from '@mui/joy/IconButton';
import { Tooltip } from '@mui/joy';

const Windows = (): ReactElement => {
  // const inspectorSize = useAppSelector(selectInspectorSize);

  const [filter, setFilter] = useState({ flagged: false });
  const [groupByWindow, setGroupByWindow] = useState(true);
  const [sortOrder, setSortOrder] = useState(PageSortOrder.recent);

  const tabvanaWindowId = useLiveQuery(() => {
    return getTabvanaWindowId();
  }, []);

  const windowsSorted = useAppSelector((state: RootState) =>
    selectWindowsSortedExcept(state, tabvanaWindowId)
  );
  const tabs = useAppSelector(selectTabs);
  const dispatch = useAppDispatch();
  const duplicateUrls = useAppSelector(selectDuplicateUrls);
  const similarUrls = useAppSelector(selectSimilarUrls);
  const selectedUrls = useAppSelector(selectSelectedUrls);

  // Data for Flat View
  const allTabIds = useMemo(() => {
     if (!windowsSorted) return [];
     return windowsSorted.flatMap(([_, w]) => w.tabIds);
  }, [windowsSorted]);

  const allTabObjects = useMemo(() => allTabIds.map(id => tabs[id]).filter(t => t && t.url), [allTabIds, tabs]);
  const allUrls = useMemo(() => allTabObjects.map(t => t.url!.normalized), [allTabObjects]);
  
  const pages = useLiveQuery(() => fetchPages(allUrls), [allUrls]);

  let content;
  if (!windowsSorted) {
      content = <></>;
  } else if (groupByWindow) {
      content = windowsSorted.map(([windowId, window]) => (
        <WindowTabList key={windowId} windowId={Number(windowId)} filter={filter} sortOrder={sortOrder} />
      ));
  } else {
      if (!pages) {
          content = <></>; // Loading?
      } else {
          const pageMap = new Map(pages.map(p => [p.nurl.normalized, p]));
          
          // Enhance tabs
          const enrichedTabs = allTabObjects.map(tab => ({
              tab,
              page: pageMap.get(tab.url!.normalized)
          })).filter(item => item.page); 
          
          // Filter
          const filteredItems = enrichedTabs.filter(item => filterPage(item.page!, filter)); 
          
          let sortedItems = filteredItems;
          
          if (sortOrder === PageSortOrder.similarity) {
              sortedItems = sortBy(filteredItems, [
                  (item) => !selectedUrls.includes(item.page!.nurl.normalized),
                  (item) => -(similarUrls[item.page!.nurl.normalized] || 0)
              ]);
          } else if (sortOrder !== PageSortOrder.recent) {
              sortedItems = sortBy(filteredItems, (item) => pageSortOrderMap[sortOrder](item.page!));
          }

          content = (
              <div 
                style={{
                    border: '1px solid',
                    margin: '0.5rem 0.5rem 0.5rem 0.5rem',
                    borderColor: 'rgb(50, 56, 62)',
                }}
              >
                {sortedItems.map(item => (
                    <PageRow 
                        key={item.tab.id} 
                        page={item.page!} 
                        windowId={item.tab.windowId} 
                        tabId={item.tab.id} 
                    />
                ))}
            </div>
          );
      }
  }

  const dedupButton = duplicateUrls.length > 0 && (
    <Tooltip title="Deduplicate" placement="bottom">
      <IconButton
        size="sm"
        variant="soft"
        color="danger"
        onClick={() => dispatch(dedupAll())}
        title="Deduplicate"
      >
        <FontAwesomeIcon icon={faClone} />
        <span style={{ marginLeft: 5 }}>{duplicateUrls.length}</span>
      </IconButton>
    </Tooltip>
  );

  return (
    /* this lib is incompatible with react18. To fix
     children: React.ReactNode; needs to be added to SplitPaneProps.
     @ts-ignore TS2322 */
    <SplitPane
      allowResize={true}
      split="vertical"
      defaultSize={300} // inspectorSize
      minSize={10}
      primary="second"
      // onDragFinished={(size) => dispatch(setInspectorSize(size))}
    >
      <div className="fill flexContainerHorizontal">
        <div
          className="flexFillHorizontal"
          style={{
            overflow: 'scroll',
          }}
        >
          {content}
        </div>

        <div
          style={{
            borderLeft: '1px solid',
            borderColor: 'rgb(50, 56, 62)',
            height: '100%',
          }}
        ></div>
      </div>
      <Inspector
        onSelectAll={() => {
          // Select all visible
          if (!windowsSorted) return;
          // Reuse logic from content generation? expensive.
          // Just gather all available tabs in windowsSorted, pass to selector, relying on reducer to handle.
          // Usually selecting all involves selecting the items that are visible.
          // If filtered/sorted, we should select only those?
          // Existing logic selected ALL in windows irrespective of filter?
          // Existing logic:
          // const allTabsInWindows = windowsSorted.flatMap(...)
          // dispatch(clearSelectionAndSelectMulti(...))
          
          // We probably want to respect the Filter at least.
          // But implementing exact "visible items" might be duplicated logic.
          // For now, let's keep selecting all open tabs as a safe default or improve it.
          // Given the user request is about sorting/grouping, let's stick to "select all open tabs" for now or
          // try to approximate if filter is on.
          
          const allTabsInWindows = windowsSorted
            .flatMap(([, window]) => window.tabIds)
            .map((tabId) => tabs[tabId])
            .filter((tab) => tab != null && tab.url != null);
            
          let finalTabs = allTabsInWindows;
          
          // If we have access to loaded pages, we can filter.
          if (pages && filter.flagged) {
             const pageMap = new Map(pages.map(p => [p.nurl.normalized, p]));
             finalTabs = allTabsInWindows.filter(t => {
                 const p = pageMap.get(t.url!.normalized);
                 return p && filterPage(p, filter);
             });
          }

          dispatch(
            clearSelectionAndSelectMulti({
              urls: finalTabs.map((t) => ({ normalized: t.url!.normalized } as any)),
            })
          );
        }}
      >
        <FlexViewHeader
          tagsSorted={[]}
          sortOrder={sortOrder}
          setSortOrder={setSortOrder}
          filter={filter}
          setFilter={setFilter}
          groupByWindow={groupByWindow}
          setGroupByWindow={setGroupByWindow}
        >
            {dedupButton}
        </FlexViewHeader>
      </Inspector>
    </SplitPane>
  );
};

export default Windows;
