import * as vscode from 'vscode';
import * as path from 'path';
import { getWebviewContent } from './webview';
import { uploadFileHandler } from './handler/uploadFile';

// 状态管理器
// 更简化的状态对象
const state = {
  panel: undefined as vscode.WebviewPanel | undefined,
  targetEditor: undefined as vscode.TextEditor | undefined,
  webviewMsgDisposable: undefined as vscode.Disposable | undefined,
  extPath: '',
  scrollTimeout: undefined as ReturnType<typeof setTimeout> | undefined,
  editTimeout: undefined as ReturnType<typeof setTimeout> | undefined,
  disableScroll: false,
  disableEdit: false,
  isPanelInit: false,
  theme: vscode.workspace.getConfiguration('cherryMarkdown').get('theme') as string | undefined,
  reset() {
    if (this.scrollTimeout) clearTimeout(this.scrollTimeout);
    if (this.editTimeout) clearTimeout(this.editTimeout);
    this.webviewMsgDisposable?.dispose();
    this.panel = undefined;
    this.targetEditor = undefined;
    this.webviewMsgDisposable = undefined;
    this.scrollTimeout = undefined;
    this.editTimeout = undefined;
    this.disableScroll = false;
    this.disableEdit = false;
    this.isPanelInit = false;
    this.theme = vscode.workspace.getConfiguration('cherryMarkdown').get('theme') as string | undefined;
  },
};

export function activate(context: vscode.ExtensionContext) {
  state.extPath = context.extensionPath;
  context.subscriptions.push(
    vscode.commands.registerCommand('cherrymarkdown.preview', () => triggerEditorContentChange(true)),
  );
  context.subscriptions.push(vscode.workspace.onDidOpenTextDocument(() => triggerEditorContentChange()));
  context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor((e) => handleActiveEditorChange(e)));
  context.subscriptions.push(
    vscode.workspace.onDidChangeTextDocument((e) => {
      if (state.isPanelInit && e?.document && !state.disableEdit) {
        triggerEditorContentChange();
      }
    }),
  );
  context.subscriptions.push(
    vscode.window.onDidChangeTextEditorVisibleRanges((e) => {
      if (!state.isPanelInit || !state.panel) return;
      if (!state.disableScroll) {
        state.panel.webview.postMessage({ cmd: 'editor-scroll', data: e.visibleRanges[0].start.line });
      }
    }),
  );
}

// this method is called when your extension is deactivated
export function deactivate() {}

/**
 * 获取当前文件的信息
 * @returns
 */
const getMarkdownFileInfo = () => {
  let editor = vscode.window.activeTextEditor;
  let doc = editor?.document;
  let text = '';
  let title = '';
  if (doc?.languageId !== 'markdown' && state.targetEditor?.document?.languageId === 'markdown') {
    editor = state.targetEditor;
    doc = state.targetEditor?.document;
  }
  if (doc?.languageId === 'markdown' && editor) {
    state.targetEditor = editor;
    text = doc.getText() || '';
    title = path.basename(doc.fileName) || '';
  }
  title = title
    ? `${vscode.l10n.t('Preview')} ${title} ${vscode.l10n.t('By')} Cherry Markdown`
    : `${vscode.l10n.t('UnSupported')} ${vscode.l10n.t('By')} Cherry Markdown`;
  const theme = state.theme ?? vscode.workspace.getConfiguration('cherryMarkdown').get('theme');
  return { mdInfo: { text, theme }, currentTitle: title };
};

/**
 * 初始化cherry预览窗口
 */
const initCherryPanel = () => {
  if (state.isPanelInit && state.panel) {
    state.panel.reveal(vscode.ViewColumn.Two);
    return;
  }
  const { mdInfo, currentTitle } = getMarkdownFileInfo();
  const workspaceFolder = vscode.workspace.workspaceFolders?.[0].uri.fsPath ?? '';
  state.panel = vscode.window.createWebviewPanel('cherrymarkdown.preview', currentTitle, vscode.ViewColumn.Two, {
    enableScripts: true,
    retainContextWhenHidden: true,
    localResourceRoots: [
      vscode.Uri.file(path.join(state.extPath, 'web-resources')),
      vscode.Uri.file(path.join(state.extPath, 'web-resources', 'dist')),
      vscode.Uri.file(workspaceFolder),
    ],
  });
  try {
    state.panel.webview.html = getWebviewContent(
      { ...mdInfo, vscodeLanguage: vscode.env.language },
      state.panel,
      state.extPath,
    );
  } catch (err) {
    vscode.window.showErrorMessage('Failed to initialize Cherry Markdown webview.');
    console.error(err);
  }
  state.panel.iconPath = vscode.Uri.file(path.join(state.extPath, 'favicon.ico'));
  state.isPanelInit = true;
  state.panel.onDidDispose(() => state.reset());
  initCherryPanelEvent();
};

const initCherryPanelEvent = () => {
  if (!state.panel) return;
  state.webviewMsgDisposable?.dispose();
  state.webviewMsgDisposable = state.panel.webview.onDidReceiveMessage(async (e) => {
    const { type, data } = e;
    switch (type) {
      case 'preview-scroll': {
        state.disableScroll = true;
        if (!state.targetEditor) return;
        const pos = new vscode.Position(data, 0);
        const range = new vscode.Range(pos, pos);
        state.targetEditor.revealRange(range, vscode.TextEditorRevealType.AtTop);
        if (state.scrollTimeout) clearTimeout(state.scrollTimeout);
        state.scrollTimeout = setTimeout(() => {
          state.disableScroll = false;
        }, 500);
        return;
      }
      case 'change-theme': {
        state.theme = data;
        vscode.workspace.getConfiguration('cherryMarkdown').update('theme', data, true);
        break;
      }
      case 'cherry-change': {
        if (!state.targetEditor) break;
        state.disableEdit = true;
        state.targetEditor.edit((editBuilder) => {
          const endNum = state.targetEditor!.document.lineCount + 1;
          const end = new vscode.Position(endNum, 0);
          editBuilder.replace(new vscode.Range(new vscode.Position(0, 0), end), data.markdown);
        });
        if (state.editTimeout) clearTimeout(state.editTimeout);
        state.editTimeout = setTimeout(() => {
          state.disableEdit = false;
        }, 500);
        break;
      }
      case 'tips':
        vscode.window.showInformationMessage(data, 'OK');
        break;
      case 'cherry-load-img':
        // 可扩展图片加载逻辑
        break;
      case 'upload-file': {
        try {
          const res = await uploadFileHandler(data);
          if (res.url) {
            state.panel?.webview.postMessage({ cmd: 'upload-file-callback', data: res });
          } else {
            vscode.window.showInformationMessage('上传不成功');
          }
        } catch (err) {
          vscode.window.showErrorMessage('上传失败');
          console.error(err);
        }
        break;
      }
      case 'open-url': {
        if (data === 'href-invalid') {
          vscode.window.showErrorMessage('link is not valid, please check it.');
          return;
        }
        if (/^(http|https):\/\//.test(data)) {
          vscode.env.openExternal(vscode.Uri.parse(data));
          return;
        }
        const decodedData = decodeURIComponent(data);
        if (path.isAbsolute(decodedData)) {
          const decodedDataPath = vscode.Uri.file(decodedData);
          vscode.commands.executeCommand('vscode.open', decodedDataPath, { preview: true });
          return;
        }
        if (data.startsWith('#')) return;
        if (!state.targetEditor) return;
        const uri = vscode.Uri.file(path.join(state.targetEditor.document.uri.fsPath, '..', data));
        vscode.commands.executeCommand('vscode.open', uri, { preview: true });
        break;
      }
      case 'export-png': {
        if (data === 'export-fail') {
          vscode.window.showErrorMessage('导出错误,请重新尝试');
          return;
        }
        const uri = await vscode.window.showSaveDialog({
          filters: { Images: ['png'] },
          saveLabel: '保存截图',
        });
        if (uri) {
          const base64Data = data.replace(/^data:image\/png;base64,/, '');
          const buffer = Buffer.from(base64Data, 'base64');
          await vscode.workspace.fs.writeFile(uri, buffer);
          vscode.window.showInformationMessage('Image saved successfully!');
        } else {
          vscode.window.showWarningMessage('Save cancelled.');
        }
        break;
      }
    }
  });
};

// handle active editor change
const handleActiveEditorChange = (e: vscode.TextEditor | undefined) => {
  const cherryUsage = vscode.workspace.getConfiguration('cherryMarkdown').get<'active' | 'only-manual'>('Usage');
  if (!e?.document || cherryUsage !== 'active') return;
  triggerEditorContentChange();
  if (e.document.languageId !== 'markdown') {
    state.panel?.webview.postMessage({ cmd: 'disable-edit', data: {} });
  } else {
    state.panel?.webview.postMessage({ cmd: 'enable-edit', data: {} });
  }
};

/**
 * 向预览区发送vscode编辑区内容变更的消息
 */
const triggerEditorContentChange = (focus = false) => {
  if (state.isPanelInit && state.panel) {
    const { mdInfo, currentTitle } = getMarkdownFileInfo();
    state.panel.title = currentTitle;
    state.panel.webview.postMessage({ cmd: 'editor-change', data: mdInfo });
    return;
  }
  if (vscode.window.activeTextEditor?.document?.languageId === 'markdown') {
    const cherryUsage = vscode.workspace.getConfiguration('cherryMarkdown').get<'active' | 'only-manual'>('Usage');
    if (cherryUsage === 'active' || focus) {
      initCherryPanel();
    }
  }
};