import React, {useCallback, useEffect, useRef, useState} from 'react';
import * as monaco from 'monaco-editor';
import {Button} from '@/components/ui/button';
import {Tabs, TabsContent, TabsList, TabsTrigger} from '@/components/ui/tabs';
import {Card, CardContent} from '@/components/ui/card';
import LayoutGrid from '../layout/LayoutGrid';
import LayoutTreeDataGrid from '../layout/LayoutTreeDataGrid';
import ApiLayoutItemTreeBuilder from '../../lib/ApiLayoutItemTreeBuilder';
import ApiLayoutItemTreeDataBuilder from '../../lib/ApiLayoutItemTreeDataBuilder';
import VariableSnippet from '../shared/VariableSnippet';
import APIClient from '@/services/APIClient.js';

export const TCPClientView = ({ parent, serverManager, model, index }) => {
  const [apiClient] = useState(() => new APIClient());
  const [isLoading, setIsLoading] = useState(false);
  const [editors, setEditors] = useState({
    layoutJson: null,
    requestBody: null,
    responseBody: null,
    console: null,
    preRequest: null,
    postRequest: null
  });
  const [layoutData, setLayoutData] = useState(null);

  // Refs
  const layoutJsonRef = useRef(null);
  const requestBodyRef = useRef(null);
  const responseBodyRef = useRef(null);
  const consoleRef = useRef(null);
  const preRequestRef = useRef(null);
  const postRequestRef = useRef(null);
  const totalMessageLengthRef = useRef(null);
  const layoutGridRef = useRef(null);

  const handleResponseDisplay = useCallback((response) => {
    try {
      editors.responseBody?.setValue(response.body || '');
      if (response.time) {
        const responseTimeEl = document.querySelector('.response_time');
        if (responseTimeEl) {
          responseTimeEl.textContent = `time: ${response.time}ms`;
        }
      }
      if (response.size) {
        const responseSizeEl = document.querySelector('.response_size');
        if (responseSizeEl) {
          responseSizeEl.textContent = `size: ${response.size}bytes`;
        }
      }
    } catch (error) {
      console.error('Error displaying response:', error);
    }
  }, [editors.responseBody]);

  const handleLoadLayout = useCallback(() => {
    try {
      const newLayout = JSON.parse(editors.layoutJson?.getValue() || '{}');
      model.layout = newLayout;
      if (newLayout.layoutItems) {
        newLayout.layoutItems.forEach((item) => {
          if (item.value === undefined) {
            item.value = '';
          }
        });
      }

      const layoutRoot = ApiLayoutItemTreeBuilder.createTree(newLayout.layoutItems);
      const replicator = new ApiLayoutItemTreeDataBuilder(10000);
      const layoutDataRoot = replicator.createReplicatedTree(layoutRoot);

      setLayoutData(layoutDataRoot);

      if (layoutGridRef.current) {
        layoutGridRef.current.rebuild(newLayout);
      }
    } catch (error) {
      console.error('Error loading layout:', error);
      alert(error.message);
    }
  }, [model, editors.layoutJson]);

  const handleSendRequest = useCallback(async () => {
    if (!model.server) {
      alert('서버를 등록해주세요.');
      return;
    }

    setIsLoading(true);
    try {
      editors.responseBody?.setValue('');
      editors.console?.setValue('');

      const startTime = Date.now();
      const response = await apiClient.sendAPIRequest(
          model,
          null,
          (message) => {
            const consoleEditor = editors.console;
            if (consoleEditor) {
              const model = consoleEditor.getModel();
              if (model) {
                const lastLine = model.getLineCount();
                const range = new monaco.Range(lastLine, 1, lastLine, 1);
                const text = typeof message === 'object' ? JSON.stringify(message, null, 2) : message;
                consoleEditor.executeEdits('console', [{
                  identifier: { major: 1, minor: 1 },
                  range,
                  text: text + '\n',
                  forceMoveMarkers: true
                }]);
              }
            }
          }
      );

      if (response) {
        const endTime = Date.now();
        response.time = endTime - startTime;
        handleResponseDisplay(response);
      }
    } catch (error) {
      console.error('Error sending request:', error);
      alert(error.message);
    } finally {
      setIsLoading(false);
    }
  }, [model, editors, apiClient, handleResponseDisplay]);

  const handleResize = useCallback(() => {
    Object.values(editors).forEach(editor => {
      if (editor) {
        editor.layout({ width: 0 });
        editor.layout();
      }
    });
  }, [editors]);

  // Layout update handler
  const handleLayoutUpdate = useCallback(async (finalMessage, layoutDataTree) => {
    const prefix = (model.server && model.server.serverOptions)
        ? await serverManager.renderServerPrefix(model.server.serverOptions, model)
        : '';

    editors.requestBody?.setValue(prefix + finalMessage);
    model.layout.computedLayoutItemRoot = layoutDataTree;
  }, [model, editors.requestBody, serverManager]);

  // Initialize Monaco editors
  useEffect(() => {
    if (layoutJsonRef.current && !editors.layoutJson) {
      const layoutJson = JSON.stringify(model.layout, null, 2);
      const layoutJsonEditor = monaco.editor.create(layoutJsonRef.current, {
        value: layoutJson,
        language: 'json',
        automaticLayout: true,
        quickSuggestions: false
      });

      layoutJsonEditor.onDidChangeModelContent(() => {
        try {
          const content = layoutJsonEditor.getValue();
          JSON.parse(content); // Validate JSON
        } catch (e) {
          // Invalid JSON - ignore
        }
      });

      setEditors(prev => ({ ...prev, layoutJson: layoutJsonEditor }));
    }

    if (requestBodyRef.current && !editors.requestBody) {
      const requestBodyEditor = monaco.editor.create(requestBodyRef.current, {
        value: model.requestBody || '',
        language: 'text',
        automaticLayout: true,
        quickSuggestions: false
      });

      requestBodyEditor.onDidChangeModelContent(() => {
        model.requestBody = requestBodyEditor.getValue();
      });

      requestBodyEditor.onMouseMove((e) => {
        const position = e.target.position;
        if (position) {
          const editorModel = requestBodyEditor.getModel();
          if (!editorModel) return;

          const word = editorModel.getWordAtPosition(position);
          const lineContent = editorModel.getLineContent(position.lineNumber);

          if (word && lineContent.includes(`{{${word.word}}}`)) {
            parent?.showPopper?.(e.target.element, word.word);
          } else {
            parent?.hidePopper?.(e.target.element);
          }
        }
      });

      setEditors(prev => ({ ...prev, requestBody: requestBodyEditor }));
    }

    if (responseBodyRef.current && !editors.responseBody) {
      const responseBodyEditor = monaco.editor.create(responseBodyRef.current, {
        value: '',
        language: 'text',
        automaticLayout: true,
        quickSuggestions: false,
        readOnly: true
      });
      setEditors(prev => ({ ...prev, responseBody: responseBodyEditor }));
    }

    if (consoleRef.current && !editors.console) {
      const consoleEditor = monaco.editor.create(consoleRef.current, {
        value: '',
        automaticLayout: true,
        quickSuggestions: false,
        readOnly: true
      });
      setEditors(prev => ({ ...prev, console: consoleEditor }));
    }

    if (preRequestRef.current && !editors.preRequest) {
      const preRequestEditor = monaco.editor.create(preRequestRef.current, {
        value: model.preRequestScript || '',
        language: 'javascript',
        automaticLayout: true,
        quickSuggestions: false
      });

      preRequestEditor.onDidChangeModelContent(() => {
        model.preRequestScript = preRequestEditor.getValue();
      });

      setEditors(prev => ({ ...prev, preRequest: preRequestEditor }));
    }

    if (postRequestRef.current && !editors.postRequest) {
      const postRequestEditor = monaco.editor.create(postRequestRef.current, {
        value: model.postRequestScript || '',
        language: 'javascript',
        automaticLayout: true,
        quickSuggestions: false
      });

      postRequestEditor.onDidChangeModelContent(() => {
        model.postRequestScript = postRequestEditor.getValue();
      });

      setEditors(prev => ({ ...prev, postRequest: postRequestEditor }));
    }

    // Initialize layout data
    const layoutRoot = ApiLayoutItemTreeBuilder.createTree(model.layout.layoutItems);
    const replicator = new ApiLayoutItemTreeDataBuilder(10000);
    const layoutDataRoot = replicator.createReplicatedTree(layoutRoot);
    setLayoutData(layoutDataRoot);

    return () => {
      Object.values(editors).forEach(editor => editor?.dispose());
    };
  }, []);

  // Handle window resize
  useEffect(() => {
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, [handleResize]);

  // Tab change handlers
  useEffect(() => {
    const handleTabChange = (tab) => {
      const currentEditor = {
        'requestBodyTab': editors.requestBody,
        'preRequestTab': editors.preRequest,
        'postRequestTab': editors.postRequest
      }[tab];

      if (currentEditor) {
        currentEditor.layout();
      }
    };

    const tabs = ['requestBodyTab', 'preRequestTab', 'postRequestTab'];
    tabs.forEach(tab => {
      const element = document.querySelector(`#api_request_${model.id} .btn_${tab}`);
      if (element) {
        const handler = () => handleTabChange(tab);
        element.addEventListener('shown.bs.tab', handler);
        return () => element.removeEventListener('shown.bs.tab', handler);
      }
    });
  }, [editors, model.id]);

  // Server options effect
  useEffect(() => {
    if (!model.server) return;

    if (model.server.headers === undefined) {
      model.server.headers = [];
    }

    if (model.server.serverOptions) {
      serverManager.renderTcpServerOptions(
          '.server_options',
          model.server.serverOptions,
          model.headers,
          parent
      );
    }
  }, [model.server, model.headers, parent, serverManager]);

  return (
      <div className="flex flex-col h-full p-4">
        {/* Header Section */}
        <div className="flex items-center space-x-2 mb-4">
        <span className="text-sm text-muted-foreground">
          {model.collectionName} &gt; {model.name}
        </span>
        </div>

        {/* Server Selection */}
        <div className="flex items-center space-x-2 mb-4">
          <div className="form-floating">
            {serverManager.renderTcpServers(model.server)}
            <label className="text-sm text-muted-foreground">Server</label>
          </div>
          <Button
              onClick={handleSendRequest}
              disabled={isLoading}
          >
            {isLoading ? 'Sending...' : 'Send'}
          </Button>
          <Button
              onClick={() => parent?.handleSaveRequest?.(model)}
              disabled={isLoading}
          >
            Save
          </Button>
        </div>

        {/* Server Options */}
        <div className="server_options mb-4" />

        {/* Main Content */}
        <Tabs defaultValue="layout" className="flex-1">
          <TabsList>
            <TabsTrigger value="layout">Layout</TabsTrigger>
            <TabsTrigger value="layoutJson">Layout JSON</TabsTrigger>
            <TabsTrigger value="layoutTree">Layout Tree</TabsTrigger>
            <TabsTrigger value="layoutData">Layout Data</TabsTrigger>
            <TabsTrigger value="preRequest">Pre-Request</TabsTrigger>
            <TabsTrigger value="postRequest">Post-Request</TabsTrigger>
          </TabsList>

          <TabsContent value="layout">
            <div ref={layoutGridRef}>
              <LayoutGrid
                  layout={model.layout}
                  onChange={(updatedLayout) => {
                    model.layout = updatedLayout;
                    editors.layoutJson?.setValue(JSON.stringify(updatedLayout, null, 2));
                  }}
              />
            </div>
          </TabsContent>

          <TabsContent value="layoutJson">
            <div className="flex flex-col gap-4">
              <div ref={layoutJsonRef} className="h-[300px] border" />
              <Button
                  onClick={handleLoadLayout}
                  disabled={isLoading}
              >
                레이아웃 불러오기
              </Button>
            </div>
          </TabsContent>

          <TabsContent value="layoutData">
            <div className="flex flex-col gap-4">
              <div className="border h-[400px] overflow-auto">
                {layoutData && (
                    <LayoutTreeDataGrid
                        root={layoutData}
                        apiRequest={model}
                        options={layoutDataTreeOptions}
                        totalMessageLengthSelector={totalMessageLengthRef.current}
                        onUpdate={handleLayoutUpdate}
                    />
                )}
              </div>
            </div>
          </TabsContent>

          <TabsContent value="preRequest">
            <div className="flex gap-4">
              <div className="flex-1">
                <div ref={preRequestRef} className="h-[300px] border" />
              </div>
              <div className="w-48">
                <VariableSnippet editor={editors.preRequest} />
              </div>
            </div>
          </TabsContent>

          <TabsContent value="postRequest">
            <div className="flex gap-4">
              <div className="flex-1">
                <div ref={postRequestRef} className="h-[300px] border" />
              </div>
              <div className="w-48">
                <VariableSnippet editor={editors.postRequest} />
              </div>
            </div>
          </TabsContent>
        </Tabs>

        {/* Message Length */}
        <div className="mt-4 flex items-center space-x-2">
          <span>전체 메시지 길이:</span>
          <span ref={totalMessageLengthRef} />
        </div>

        {/* Response Section */}
        <Card className="mt-4">
          <CardContent>
            <div className="flex flex-col">
              <div className="flex items-center gap-2 mb-2">
                <span>Response</span>
                <span className="response_time" />
                <span className="response_size" />
              </div>
              <Tabs defaultValue="body">
                <TabsList>
                  <TabsTrigger value="body">Body</TabsTrigger>
                  <TabsTrigger value="console">Console</TabsTrigger>
                </TabsList>

                <TabsContent value="body">
                  <div ref={responseBodyRef} className="h-[250px] border" />
                </TabsContent>

                <TabsContent value="console">
                  <div ref={consoleRef} className="h-[250px] border" />
                </TabsContent>
              </Tabs>
            </div>
          </CardContent>
        </Card>
      </div>
  );
};

// export default TCPClientView;
