
import type StatedScreen from '../StatedScreen';
import type { CssInsertRule, CssDeleteRule } from '../messages';
import type { Timed } from '../Timed';

type CSSRuleMessage = CssInsertRule | CssDeleteRule;
type TimedCSSRuleMessage = Timed & CSSRuleMessage;

import logger from 'App/logger';
import ListWalker from './ListWalker';


const HOVER_CN = "-openreplay-hover";
const HOVER_SELECTOR = `.${HOVER_CN}`;

// Doesn't work with css files (hasOwnProperty)
export function rewriteNodeStyleSheet(doc: Document, node: HTMLLinkElement | HTMLStyleElement) {
  const ss = Object.values(doc.styleSheets).find(s => s.ownerNode === node);
  if (!ss || !ss.hasOwnProperty('rules')) { return; }
  for(let i = 0; i < ss.rules.length; i++){
    const r = ss.rules[i]
    if (r instanceof CSSStyleRule) {
      r.selectorText = r.selectorText.replace('/\:hover/g', HOVER_SELECTOR)
    }
  }
}

export default class StylesManager extends ListWalker<TimedCSSRuleMessage> {
  private linkLoadingCount: number = 0;
  private linkLoadPromises: Array<Promise<void>> = [];
  private skipCSSLinks: Array<string> = []; // should be common for all pages

  constructor(private readonly screen: StatedScreen) {
    super();
  }

  reset():void {
    super.reset();
    this.linkLoadingCount = 0;
    this.linkLoadPromises = [];

    //cancel all promises? tothinkaboutit
  }

  setStyleHandlers(node: HTMLLinkElement, value: string): void {
    let timeoutId;
    const promise = new Promise((resolve) => {
      if (this.skipCSSLinks.includes(value)) resolve(null);
      this.linkLoadingCount++;
      this.screen.setCSSLoading(true);
      const addSkipAndResolve = () => {
        this.skipCSSLinks.push(value); // watch out
        resolve(null);
      }
      timeoutId = setTimeout(addSkipAndResolve, 4000);

      node.onload = () => {
        const doc = this.screen.document;
        doc && rewriteNodeStyleSheet(doc, node);
        resolve(null);
      }
      node.onerror = addSkipAndResolve;
    }).then(() => {
      node.onload = null;
      node.onerror = null;
      clearTimeout(timeoutId);
      this.linkLoadingCount--;
      if (this.linkLoadingCount === 0) {
        this.screen.setCSSLoading(false);
      }
    });
    this.linkLoadPromises.push(promise);
  }

  private manageRule = (msg: CSSRuleMessage):void => {
    // if (msg.tp === "css_insert_rule") {
    //   let styleSheet = this.#screen.document.styleSheets[ msg.stylesheetID ];
    //   if (!styleSheet) { 
    //     logger.log("No stylesheet with corresponding ID found: ", msg)
    //     styleSheet = this.#screen.document.styleSheets[0];
    //     if (!styleSheet) {
    //       return;
    //     }
    //   }
    //   try {
    //     styleSheet.insertRule(msg.rule, msg.index);
    //   } catch (e) {
    //     logger.log(e, msg)
    //     //const index = Math.min(msg.index, styleSheet.cssRules.length);
    //     styleSheet.insertRule(msg.rule, styleSheet.cssRules.length);
    //     //styleSheet.ownerNode.innerHTML += msg.rule;
    //   }
    // }
    // if (msg.tp === "css_delete_rule") {
    //   // console.warn('Warning: STYLESHEET_DELETE_RULE msg')
    //   const styleSheet = this.#screen.document.styleSheets[msg.stylesheetID];
    //   if (!styleSheet) { 
    //     logger.log("No stylesheet with corresponding ID found: ", msg)
    //     return; 
    //   }
    //   styleSheet.deleteRule(msg.index);
    // }
  }

  moveReady(t: number): Promise<void> {
    return Promise.all(this.linkLoadPromises)
      .then(() => this.moveApply(t, this.manageRule));
  }
}