import { ReactElement, useState, useEffect } from 'react';
import { Menu, MenuItem, Modal, ModalDialog, ModalClose, DialogTitle, DialogContent, Tooltip, IconButton, Checkbox, Input, FormLabel, FormControl, Button, Stack, LinearProgress, Typography, Select, Option } from '@mui/joy';

import './PageRow.less';

import { InView } from 'react-intersection-observer';
import { activateOrOpenTab } from '../../../../chrome/chromeNavigation';
import { Page } from '../../../../db/pages';
import { useAppSelector, useAppDispatch } from '../../../../store/hooks';
import {
  selectSelectedUrls,
  toggleSelected,
  clearSelectionAndSelect,
  rangeSelected,
  constructPageRowId,
  selectSimilarUrls,
} from '../../../../store/uiSlice';
import {
  selectTabsForPage,
  selectIsActiveTab,
  selectIsDuplicate,
  setSimilarUrlsAsync,
  searchSimilarAsync,
  updateWindowsAsync,
} from '../../../../store/windowsSlice';
import { updateTodoCompletion, updateTodoTitle, updateTodoPriority, updateTodoDueDate, convertPageToTodo, removePageTodoStatus } from '../../../../db/pages';
import { getIgnoredUrls, setIgnoredUrls, getNormalizeRules, setNormalizeRules, getSimilarityScaler } from '../../../../db/prefs';
import { updateUrlNormalizationCache, getIgnoredSubstrings, getNormalizeUrlRegexes } from '../../../../db/urlNormalizationPrefs';
import { enqueueOperation } from '../../../../db/queue';
import { useLiveQuery } from 'dexie-react-hooks';
import React from 'react';
import PageTags from './PageTags';

function tsToDateInputValue(ts: number): string {
  const d = new Date(ts);
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
}

function dateInputValueToTs(s: string): number {
  const [y, mo, day] = s.split('-').map(Number);
  return new Date(y, mo - 1, day).getTime();
}
import PageInfo from '../../../inspector/PageInfo';
import { logger } from '../../../../utils/logger';
import { faEquals, faListCheck } from '@fortawesome/free-solid-svg-icons';
import { faSquare, faSquareCheck } from '@fortawesome/free-regular-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';

interface PageRowProps {
  page: Page;
  windowId?: number;
  tabId?: number;
}

const PageRow = React.memo(
  ({ page, windowId = undefined, tabId = undefined }: PageRowProps): ReactElement => {
    const tabs = useAppSelector((state) => selectTabsForPage(state, page.nurl));
    const isOpen = tabs.length > 0;
    const isActive = useAppSelector((state) => selectIsActiveTab(state, windowId, tabId));
    const focusedWindowId = useAppSelector((state) => state.windows.focusedWindowId);
    const isDuplicate = useAppSelector((state) => selectIsDuplicate(state, page.nurl));
    const selectedUrls = useAppSelector(selectSelectedUrls);
    const similarUrls = useAppSelector(selectSimilarUrls);
    const similarityScaler = useLiveQuery(getSimilarityScaler) ?? 5;

    const similarity = Math.min(similarUrls[page.nurl.normalized] || 0, 1.0);
    const scaledSimilarity = Math.min(similarity * similarityScaler, 1.0);

    const dispatch = useAppDispatch();
    const isFocused = focusedWindowId === windowId && isActive;
    const isSelected = selectedUrls.includes(page.nurl.normalized);

    const [contextMenu, setContextMenu] = useState<{
      top: number;
      left: number;
    } | null>(null);
    const [debugOpen, setDebugOpen] = useState(false);
    const [automateOpen, setAutomateOpen] = useState(false);
    const [todoEditOpen, setTodoEditOpen] = useState(false);
    const [editTodoTitle, setEditTodoTitle] = useState('');
    const [editTodoPriority, setEditTodoPriority] = useState<number | null>(null);
    const [editTodoDueDate, setEditTodoDueDate] = useState('');
    const [todoFieldsExpanded, setTodoFieldsExpanded] = useState(false);
    const [ignoreDomain, setIgnoreDomain] = useState(false);
    const [ignoreText, setIgnoreText] = useState('');
    const [addNormalization, setAddNormalization] = useState(false);
    const [normalizationPattern, setNormalizationPattern] = useState('');
    const [normalizationReplacement, setNormalizationReplacement] = useState('$1');
    const [doRenormalize, setDoRenormalize] = useState(false);

    useEffect(() => {
      if (contextMenu) {
        const handleGlobalClick = () => setContextMenu(null);
        const handleKeyDown = (e: KeyboardEvent) => {
          if (e.key === 'Escape') setContextMenu(null);
        };

        // Delay adding listeners to avoid catching the event that opened the menu
        const frameId = requestAnimationFrame(() => {
          window.addEventListener('click', handleGlobalClick);
          window.addEventListener('contextmenu', handleGlobalClick);
          window.addEventListener('keydown', handleKeyDown);
        });

        return () => {
          cancelAnimationFrame(frameId);
          window.removeEventListener('click', handleGlobalClick);
          window.removeEventListener('contextmenu', handleGlobalClick);
          window.removeEventListener('keydown', handleKeyDown);
        };
      }
    }, [contextMenu]);

    const handleContextMenu = (event: React.MouseEvent) => {
      event.preventDefault();
      setContextMenu({
        top: event.clientY,
        left: event.clientX,
      });
    };

    const handleMenuClose = () => {
      setContextMenu(null);
    };

    const handleTodoEditOpen = () => {
      setEditTodoTitle(page.title ?? '');
      setEditTodoPriority(page.priority ?? null);
      setEditTodoDueDate(page.dueDate ? tsToDateInputValue(page.dueDate) : '');
      setTodoEditOpen(true);
      handleMenuClose();
    };

    const handleTodoEditSave = async () => {
      const title = editTodoTitle.trim();
      if (title) {
        await updateTodoTitle(page.nurl.normalized, title).catch((err: unknown) => logger.error('[PageRow] updateTodoTitle failed', err));
      }
      await updateTodoPriority(page.nurl.normalized, editTodoPriority ?? undefined).catch((err: unknown) => logger.error('[PageRow] updateTodoPriority failed', err));
      const dueDate = editTodoDueDate ? dateInputValueToTs(editTodoDueDate) : undefined;
      await updateTodoDueDate(page.nurl.normalized, dueDate).catch((err: unknown) => logger.error('[PageRow] updateTodoDueDate failed', err));
      setTodoEditOpen(false);
    };

    const handleAutomateClick = () => {
        // Prepare defaults
        // Ignore Domain
        let domain = '';
        try {
            const urlObj = new URL(page.nurl.original);
            domain = urlObj.hostname;
        } catch (e) {
            domain = '';
        }
        setIgnoreText(domain);
        setIgnoreDomain(false);

        // Normalization
        // Use selected URLs if current page is selected, otherwise just current page
        const targets = isSelected && selectedUrls.length > 0 ? selectedUrls : [page.nurl.normalized];
        
        // Find common prefix
        let prefix = targets[0];
        for (let i = 1; i < targets.length; i++) {
            let j = 0;
            while (j < prefix.length && j < targets[i].length && prefix[j] === targets[i][j]) {
                j++;
            }
            prefix = prefix.substring(0, j);
        }
        
        if (prefix.length > 0) {
            // Escape special chars
            const escaped = prefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
            setNormalizationPattern(`(${escaped}).*`);
        } else {
             setNormalizationPattern('');
        }
        
        setNormalizationReplacement('$1');
        setAddNormalization(false); // User must opt-in
        setDoRenormalize(false);
        
        setAutomateOpen(true);
        handleMenuClose();
    };

    const handleAutomateSave = async () => {
        if (ignoreDomain && ignoreText) {
            // Use current cache to ensure we keep defaults
            const ignored = getIgnoredSubstrings();
            if (!ignored.includes(ignoreText)) {
                const newIgnored = [...ignored, ignoreText];
                await setIgnoredUrls(newIgnored);
                // We also need to get rules to update cache fully
                const rules = getNormalizeUrlRegexes();
                updateUrlNormalizationCache(newIgnored, rules);
            }
        }
        
        if (addNormalization && normalizationPattern) {
             const rules = getNormalizeUrlRegexes();
             // Check for duplicate? Assumed user knows what they are doing.
             const newRules: [string, string][] = [...rules, [normalizationPattern, normalizationReplacement]];
             await setNormalizeRules(newRules);
             
             // Update cache
             const ignored = getIgnoredSubstrings();
             updateUrlNormalizationCache(ignored, newRules);
             
             if (doRenormalize) {
                 await enqueueOperation('renormalize', {}, 10);
                 dispatch(updateWindowsAsync());
             }
        }
        
        setAutomateOpen(false);
    };

    const id = constructPageRowId(page.nurl.normalized, windowId, tabId);

    const noicon = <div className="pagerow__noicon"></div>;

    return (
      <InView>
        {({ inView, ref, entry }) =>
          inView ? (
            <div
              ref={ref}
              id={id}
              className={
                'pagerow' +
                (isOpen ? ' pagerow__open' : '') +
                (isActive ? ' pagerow__active' : '') +
                (isFocused ? ' pagerow__focused' : '') +
                (isSelected ? ' pagerow__selected' : '')
                // (isDuplicate ? ' pagerow__duplicate' : '')
                // + (similarUrls.includes(page.nurl.normalized) ? ' similar' : '')
              }
              // style={{ ['--similarity']: similarity } as React.CSSProperties}
              onContextMenu={handleContextMenu}
            >
              <div 
                  className="pagerow__similarity-dot" 
                  style={{ opacity: scaledSimilarity }}
                  title={`Similarity: ${Math.round(similarity * 100)}% (Scaled: ${Math.round(scaledSimilarity * 100)}%)`}
              />
              {isSelected ? (
                <Tooltip title="Deselect Page" placement="right">
                  <IconButton
                    size="sm"
                    variant="plain"
                    color="neutral"
                    onClick={(event) => {
                      event.stopPropagation();
                      dispatch(toggleSelected({ url: page.nurl, id: id }));
                      dispatch(setSimilarUrlsAsync());
                    }}
                    sx={{ '--IconButton-size': '20px', minWidth: 0, minHeight: 0, p: 0 }}
                  >
                    <FontAwesomeIcon
                      className="pagerow__tagicon"
                      icon={faSquareCheck}
                    />
                  </IconButton>
                </Tooltip>
              ) : (
                <Tooltip title="Select Page" placement="right">
                  <IconButton
                    size="sm"
                    variant="plain"
                    color="neutral"
                    onClick={(event) => {
                      event.stopPropagation();
                      dispatch(toggleSelected({ url: page.nurl, id: id }));
                      dispatch(setSimilarUrlsAsync());
                    }}
                    sx={{ '--IconButton-size': '20px', minWidth: 0, minHeight: 0, p: 0 }}
                  >
                    <FontAwesomeIcon
                      className="pagerow__tagicon"
                      icon={faSquare}
                    />
                  </IconButton>
                </Tooltip>
              )}

              {isDuplicate ? (
                <Tooltip title="Duplicate Page" placement="right">
                  <IconButton
                    size="sm"
                    variant="plain"
                    color="neutral"
                    sx={{ '--IconButton-size': '20px', minWidth: 0, minHeight: 0, p: 0, cursor: 'default' }}
                  >
                    <FontAwesomeIcon className="pagerow__tagicon" icon={faEquals} color="red" />
                  </IconButton>
                </Tooltip>
              ) : (
                noicon
              )}

              {page.completionStatus !== undefined && (
                <Tooltip title={page.completionStatus === 'completed' ? 'Mark pending' : 'Mark complete'} placement="right">
                  <Checkbox
                    size="sm"
                    checked={page.completionStatus === 'completed'}
                    onChange={(e) => {
                      updateTodoCompletion(page.nurl.normalized, e.target.checked ? 'completed' : 'pending')
                        .catch(err => logger.error('[PageRow] updateTodoCompletion failed', err));
                    }}
                  />
                </Tooltip>
              )}

              <img className="pagerow__favicon" src={page.favIconUrl} />

              {page.completionStatus !== undefined && (
                <span
                  style={{
                    fontSize: '0.65em',
                    fontWeight: 'bold',
                    background: page.completionStatus === 'completed' ? '#888' : '#4a90d9',
                    color: '#fff',
                    borderRadius: 3,
                    padding: '1px 4px',
                    flexShrink: 0,
                    opacity: page.completionStatus === 'completed' ? 0.7 : 1,
                  }}
                >
                  TODO
                </span>
              )}
              {page.completionStatus !== undefined && page.priority != null && (
                <span
                  style={{
                    fontSize: '0.6em',
                    fontWeight: 'bold',
                    background: page.priority === 1 ? '#c0392b' : page.priority === 2 ? '#e67e22' : '#7f8c8d',
                    color: '#fff',
                    borderRadius: 3,
                    padding: '1px 4px',
                    flexShrink: 0,
                  }}
                >
                  {page.priority === 1 ? 'P0' : page.priority === 2 ? 'P1' : 'P2'}
                </span>
              )}
              <div
                className="pagerow__tabtitle"
                style={page.completionStatus === 'completed' ? { textDecoration: 'line-through' } : undefined}
                onDoubleClick={(event) => {
                  event.stopPropagation();
                  if (page.completionStatus !== undefined) {
                    handleTodoEditOpen();
                  } else {
                    logger.debug('[PageRow] double click', page.nurl.normalized, tabs[0]?.windowId, tabs[0]?.id);
                    void activateOrOpenTab(page.nurl.normalized, tabs[0]?.windowId, tabs[0]?.id);
                  }
                }}
                onClick={(event) => {
                  if (event.altKey) {
                    // pass
                  } else if (event.ctrlKey) {
                    dispatch(toggleSelected({ url: page.nurl, id: id }));
                    dispatch(setSimilarUrlsAsync());
                  } else if (event.metaKey) {
                    dispatch(toggleSelected({ url: page.nurl, id: id }));
                    dispatch(setSimilarUrlsAsync());
                  } else if (event.shiftKey) {
                    dispatch(rangeSelected({ url: page.nurl, id: id }));
                    dispatch(setSimilarUrlsAsync());
                  } else {
                    dispatch(
                      clearSelectionAndSelect({
                        url: page.nurl,
                        id: id,
                      })
                    );
                    dispatch(setSimilarUrlsAsync());
                  }
                }}
              >
                {page.title}
              </div>

              <PageTags page={page} tabs={tabs} />

              {page.completionStatus === undefined && (
                <span className="pagerow__hoverbuttons">
                  <Tooltip title="Mark as Todo" placement="left">
                    <IconButton
                      size="sm"
                      variant="plain"
                      color="neutral"
                      onClick={(e) => {
                        e.stopPropagation();
                        convertPageToTodo(page.nurl.normalized)
                          .catch(err => logger.error('[PageRow] convertPageToTodo failed', err));
                      }}
                      sx={{ '--IconButton-size': '18px', minWidth: 0, minHeight: 0, p: 0 }}
                    >
                      <FontAwesomeIcon icon={faListCheck} style={{ fontSize: '0.7em', color: '#888' }} />
                    </IconButton>
                  </Tooltip>
                </span>
              )}
              {page.completionStatus !== undefined && (
                todoFieldsExpanded ? (
                  <span className="pagerow__todoinline" onClick={(e) => e.stopPropagation()}>
                    <Select
                      size="sm"
                      value={page.priority ?? null}
                      onChange={(_: React.SyntheticEvent | null, val: number | null) => {
                        updateTodoPriority(page.nurl.normalized, val ?? undefined)
                          .catch(err => logger.error('[PageRow] updateTodoPriority failed', err));
                      }}
                      sx={{ minWidth: 70, fontSize: '0.65rem', '--Select-minHeight': '18px', p: '0 4px' }}
                    >
                      <Option value={null}>-</Option>
                      <Option value={1}><span style={{ color: '#c0392b', fontWeight: 'bold' }}>P0</span></Option>
                      <Option value={2}><span style={{ color: '#e67e22', fontWeight: 'bold' }}>P1</span></Option>
                      <Option value={3}><span style={{ color: '#7f8c8d', fontWeight: 'bold' }}>P2</span></Option>
                    </Select>
                    <Input
                      size="sm"
                      type="date"
                      value={page.dueDate ? tsToDateInputValue(page.dueDate) : ''}
                      onChange={(e) => {
                        const val = e.target.value;
                        updateTodoDueDate(page.nurl.normalized, val ? dateInputValueToTs(val) : undefined)
                          .catch(err => logger.error('[PageRow] updateTodoDueDate failed', err));
                      }}
                      sx={{ width: 110, fontSize: '0.65rem', '--Input-minHeight': '18px', p: '0 4px' }}
                    />
                    <span
                      className="pagerow__todotoggle"
                      title="Collapse"
                      onClick={(e) => { e.stopPropagation(); setTodoFieldsExpanded(false); }}
                    >▲</span>
                  </span>
                ) : (
                  <span className="pagerow__hoverbuttons">
                    {page.dueDate && (
                      <span style={{ fontSize: '0.6em', color: '#aaa', marginRight: 2 }}>
                        {new Date(page.dueDate).toLocaleDateString(undefined, { month: 'short', day: 'numeric' })}
                      </span>
                    )}
                    <span
                      className="pagerow__todotoggle"
                      title="Edit todo fields"
                      onClick={(e) => { e.stopPropagation(); setTodoFieldsExpanded(true); }}
                    >▼</span>
                  </span>
                )
              )}
              <Menu
                open={!!contextMenu}
                onClose={handleMenuClose}
                anchorEl={
                  contextMenu
                    ? {
                        getBoundingClientRect: () => ({
                          top: contextMenu.top,
                          left: contextMenu.left,
                          right: contextMenu.left,
                          bottom: contextMenu.top,
                          width: 0,
                          height: 0,
                          toJSON: () => {},
                          x: contextMenu.left,
                          y: contextMenu.top,
                        }),
                      }
                    : null
                }
              >
                <MenuItem
                  onClick={() => {
                    dispatch(searchSimilarAsync(page.nurl));
                    handleMenuClose();
                  }}
                >
                  Search Similar
                </MenuItem>
                {page.completionStatus !== undefined && (
                  <MenuItem onClick={handleTodoEditOpen}>
                    Edit Todo...
                  </MenuItem>
                )}
                {page.completionStatus !== undefined && (
                  <MenuItem
                    color="neutral"
                    onClick={() => {
                      removePageTodoStatus(page.nurl.normalized)
                        .catch(err => logger.error('[PageRow] removePageTodoStatus failed', err));
                      handleMenuClose();
                    }}
                  >
                    Remove Todo Status
                  </MenuItem>
                )}
                {page.completionStatus === undefined && (
                  <MenuItem
                    onClick={() => {
                      convertPageToTodo(page.nurl.normalized)
                        .catch(err => logger.error('[PageRow] convertPageToTodo failed', err));
                      handleMenuClose();
                    }}
                  >
                    Mark as Todo
                  </MenuItem>
                )}
                <MenuItem
                  onClick={() => {
                    setDebugOpen(true);
                    handleMenuClose();
                  }}
                >
                  Debug Details
                </MenuItem>
                {page.completionStatus === undefined && (
                  <MenuItem onClick={handleAutomateClick}>
                    Automate...
                  </MenuItem>
                )}
              </Menu>
              <Modal open={automateOpen} onClose={() => setAutomateOpen(false)}>
                <ModalDialog layout="center" sx={{ maxWidth: '500px' }}>
                    <ModalClose />
                    <DialogTitle>Automate Actions</DialogTitle>
                    <DialogContent>
                        <Stack spacing={2}>
                            <Stack spacing={1}>
                                <Checkbox 
                                    label="Add domain to ignore list" 
                                    checked={ignoreDomain} 
                                    onChange={(e) => setIgnoreDomain(e.target.checked)} 
                                />
                                <Input 
                                    disabled={!ignoreDomain}
                                    value={ignoreText} 
                                    onChange={(e) => setIgnoreText(e.target.value)} 
                                    placeholder="Domain to ignore"
                                />
                            </Stack>
                            <Stack spacing={1}>
                                <Checkbox 
                                    label="Add normalization rule" 
                                    checked={addNormalization} 
                                    onChange={(e) => {
                                        setAddNormalization(e.target.checked);
                                        if (e.target.checked) setDoRenormalize(true);
                                    }} 
                                />
                                <FormControl disabled={!addNormalization}>
                                    <FormLabel>Regex Pattern</FormLabel>
                                    <Input 
                                        value={normalizationPattern} 
                                        onChange={(e) => setNormalizationPattern(e.target.value)} 
                                    />
                                </FormControl>
                                <FormControl disabled={!addNormalization}>
                                    <FormLabel>Replacement</FormLabel>
                                    <Input 
                                        value={normalizationReplacement} 
                                        onChange={(e) => setNormalizationReplacement(e.target.value)} 
                                    />
                                </FormControl>
                                <Checkbox 
                                    label="Renormalize database" 
                                    disabled={!addNormalization}
                                    checked={doRenormalize} 
                                    onChange={(e) => setDoRenormalize(e.target.checked)} 
                                />
                            </Stack>
                            <Button onClick={handleAutomateSave}>Save</Button>
                        </Stack>
                    </DialogContent>
                </ModalDialog>
              </Modal>
              <Modal open={debugOpen} onClose={() => setDebugOpen(false)}>
                <ModalDialog layout="center" sx={{ maxWidth: '80vw', maxHeight: '80vh', overflow: 'auto' }}>
                  <ModalClose />
                  <DialogTitle>Debug Details</DialogTitle>
                  <DialogContent>
                    <PageInfo page={page} />
                  </DialogContent>
                </ModalDialog>
              </Modal>
              <Modal open={todoEditOpen} onClose={() => { setTodoEditOpen(false); setEditTodoTitle(''); setEditTodoPriority(null); setEditTodoDueDate(''); }}>
                <ModalDialog layout="center" sx={{ minWidth: 340 }}>
                  <ModalClose />
                  <DialogTitle>Edit Todo</DialogTitle>
                  <DialogContent>
                    <Stack spacing={2}>
                      <FormControl>
                        <FormLabel>Title</FormLabel>
                        <Input
                          autoFocus
                          value={editTodoTitle}
                          onChange={(e) => setEditTodoTitle(e.target.value)}
                          onKeyDown={(e) => {
                            if (e.key === 'Enter') void handleTodoEditSave();
                            else if (e.key === 'Escape') { setTodoEditOpen(false); setEditTodoTitle(''); setEditTodoPriority(null); setEditTodoDueDate(''); }
                          }}
                        />
                      </FormControl>
                      <FormControl>
                        <FormLabel>Priority</FormLabel>
                        <Select
                          value={editTodoPriority}
                          onChange={(_: React.SyntheticEvent | null, val: number | null) => setEditTodoPriority(val)}
                        >
                          <Option value={null}>-</Option>
                          <Option value={1}>High</Option>
                          <Option value={2}>Medium</Option>
                          <Option value={3}>Low</Option>
                        </Select>
                      </FormControl>
                      <FormControl>
                        <FormLabel>Due Date</FormLabel>
                        <Input
                          type="date"
                          value={editTodoDueDate}
                          onChange={(e) => setEditTodoDueDate(e.target.value)}
                        />
                      </FormControl>
                      <Stack direction="row" spacing={1} justifyContent="flex-end">
                        <Button variant="plain" color="neutral" onClick={() => { setTodoEditOpen(false); setEditTodoTitle(''); setEditTodoPriority(null); setEditTodoDueDate(''); }}>
                          Cancel
                        </Button>
                        <Button disabled={editTodoTitle.trim() === ''} onClick={() => void handleTodoEditSave()}>Save</Button>
                      </Stack>
                    </Stack>
                  </DialogContent>
                </ModalDialog>
              </Modal>
            </div>
          ) : (
            <div ref={ref} id={id} style={{ height: 25 }} />
          )
        }
      </InView>
    );
  }
);

export default PageRow;
