import React, {useEffect, useState} from 'react';
import {Button} from '@/components/ui/button';
import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from '@/components/ui/select';
import {Input} from '@/components/ui/input';
import {Tabs, TabsContent, TabsList, TabsTrigger} from '@/components/ui/tabs';
import EditableInput from '../shared/EditableInput';
import PropertyTable from '../shared/PropertyTable';
import ServerManager from '@/components/shared/ServerManager';
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from '@/components/ui/table.jsx';
import {useAPI} from '@/providers/APIProvider';
import MonacoEditor from '@/components/shared/MonacoEditor';
import APIClient from '@/services/APIClient.js';
import {SidebarTrigger} from '@/components/ui/sidebar.jsx';
import {Separator} from '@/components/ui/separator.jsx';

const HTTP_METHODS = [
  'POST', 'GET', 'PUT', 'DELETE', 'CONNECT',
  'HEAD', 'OPTIONS', 'TRACE', 'PATCH'
];

export const HTTPClientView = ({model, index}) => {
  const apiClient = new APIClient();
  const {getServer, updateAPIRequest} = useAPI();
  const [isLoading, setIsLoading] = useState(false);
  const [currentModel, setCurrentModel] = useState(model);
  const [basePath, setBasePath] = useState('');
  const [currentTab, setCurrentTab] = useState('body');
  const [currentResponseTab, setCurrentResponseTab] = useState('response-body');

  useEffect(() => {
    setCurrentModel(prev => ({
      ...prev,
      queryParams: model.queryParams || [],
      headers: model.headers || [],
      path: model.path || '',
      requestBody: model.requestBody || '',
      method: model.method || 'GET',
      contentType: model.contentType || 'json'
    }));
  }, [model]);

  const [responseData, setResponseData] = useState({
    headers: [],
    status: '',
    time: '',
    size: ''
  });

  const [editorContents, setEditorContents] = useState({
    requestBody: currentModel.requestBody || '',
    responseBody: '',
    consoleLog: '',
    preRequestScript: currentModel.preRequestScript || '',
    postRequestScript: currentModel.postRequestScript || ''
  });

  useEffect(() => {
    if (currentModel.server) {
      const selectedServer = getServer(currentModel.server);
      if (selectedServer) {
        setBasePath(selectedServer.basePath || '');
      }
    }
  }, [currentModel.server]);

  const handleServerChange = (serverId) => {
    setCurrentModel(prev => ({
      ...prev,
      server: serverId
    }));
  };

  const handleHeadersChange = (headers) => {
    setCurrentModel(prev => ({
      ...prev,
      headers
    }));
  };

  const handlePathChange = async (path) => {
    if (!path) {
      setCurrentModel(prev => ({
        ...prev,
        path: '',
        queryParams: []
      }));
      return;
    }
    setCurrentModel(prev => {
      const queryParams = parseQueryParams(path);
      return {
        ...prev,
        path,
        queryParams
      };
    });
  };


  const buildUrlFromPathAndParams = (path, queryParams) => {
    const baseUrl = path.split('?')[0];
    const enabledParams = queryParams.filter(p => p.enabled && p.key);

    if (!enabledParams.length) return baseUrl;

    const queryString = enabledParams
    .map(p => `${p.key}=${p.value || ''}`)
    .join('&');

    return `${baseUrl}?${queryString}`;
  };

  const handleQueryParamsChange = (newParams) => {
    const newPath = buildUrlFromPathAndParams(currentModel.path.split('?')[0], newParams);
    setCurrentModel(prev => ({
      ...prev,
      path: newPath,
      queryParams: newParams
    }));
  };


  const parseQueryParams = (path) => {
    const queryParams = [];
    const [, queryString] = path.split('?');

    if (queryString) {
      queryString.split('&').forEach(param => {
        const [key, value] = param.split('=').map(decodeURIComponent);
        if (key) {
          queryParams.push({
            enabled: true,
            key,
            value: value || ''
          });
        }
      });
    }

    return queryParams;
  };

  const handleSendRequest = async () => {
    if (isLoading) {
      return;
    }

    setIsLoading(true);
    setEditorContents(prev => ({...prev, consoleLog: ''}));

    try {
      const response = await apiClient.sendAPIRequest(
          currentModel,
          (log) => setEditorContents(prev => ({
            ...prev,
            consoleLog: prev.consoleLog + log + '\n'
          }))
      );

      const headerArray = Array.isArray(response.headers)
          ? response.headers
          : Object.entries(response.headers).map(([key, value]) => ({
            name: key,
            value: value
          }));

      setResponseData({
        headers: headerArray,
        status: `Status: ${response.status}`,
        time: `${response.time}ms`,
        size: `Size: ${response.size}`
      });

      setEditorContents(prev => ({
        ...prev,
        responseBody: response.body
      }));


    } catch (error) {
      console.error(error);
      setEditorContents(prev => ({
        ...prev,
        consoleLog: prev.consoleLog + `Error: ${error.message}\n`
      }));
    } finally {
      setIsLoading(false);
    }
  };

  const handleSave = async () => {
    try {
      const updatedModel = {
        ...currentModel,
        headers: currentModel.headers || [],
        queryParams: currentModel.queryParams || [],
        preRequestScript: editorContents.preRequestScript,
        postRequestScript: editorContents.postRequestScript,
        requestBody: currentModel.requestBody
      };

      await updateAPIRequest(updatedModel);
    } catch (error) {
      console.error('Failed to save API:', error);
    }
  };

  const renderResponseHeaders = () => (
      <Table>
        <TableHeader>
          <TableRow>
            <TableHead>Name</TableHead>
            <TableHead>Value</TableHead>
          </TableRow>
        </TableHeader>
        <TableBody>
          {responseData.headers.map((header, index) => (
              <TableRow key={index}>
                <TableCell>{header.name}</TableCell>
                <TableCell>{header.value}</TableCell>
              </TableRow>
          ))}
        </TableBody>
      </Table>
  );

  return (
      <div className="flex flex-col h-full p-4 gap-4">
        {/* Request Header Section */}
        <div className="flex items-center gap-2">
          <SidebarTrigger className="-ml-1" />
          <Separator orientation="vertical" className="mr-2 h-4" />
          <div>
            <span>{currentModel.collectionName}</span>
            {' > '}
            <span>{currentModel.name}</span>
          </div>
        </div>

        {/* Request Controls */}
        <div className="flex items-center gap-2">
          <Select value={currentModel.method} onValueChange={(value) => setCurrentModel(prev => ({...prev, method: value}))}>
            <SelectTrigger className="w-24">
              <SelectValue placeholder="Method"/>
            </SelectTrigger>
            <SelectContent>
              {HTTP_METHODS.map(method => (
                  <SelectItem key={method} value={method}>
                    {method}
                  </SelectItem>
              ))}
            </SelectContent>
          </Select>
          <div className="shrink-0">
            <ServerManager
                onServerChange={handleServerChange}
                defaultValue={currentModel.server}
            />
          </div>
          <Input value={basePath} readOnly className="w-40 shrink-0"/>
          <div className="min-w-0 flex-1">
            <EditableInput
                value={currentModel.path}
                onChange={handlePathChange}
                className="w-full"
                inputMode="text"
            />
          </div>
          <div className="flex gap-2 shrink-0">
            <Button disabled={isLoading} onClick={handleSendRequest}>
              {isLoading ? 'Sending...' : 'Send'}
            </Button>
            <Button variant="secondary" onClick={handleSave}>Save</Button>
          </div>
        </div>

        {/* Request/Response Container */}
        <div className="flex flex-col gap-4 flex-1 min-h-0">
          {/* Request Section */}
          <div className="flex-1 min-h-0">
            <Tabs value={currentTab} onValueChange={setCurrentTab} className="flex flex-col h-full">
              <TabsList>
                <TabsTrigger value="body">Body</TabsTrigger>
                <TabsTrigger value="params">Params</TabsTrigger>
                <TabsTrigger value="headers">Headers</TabsTrigger>
                <TabsTrigger value="pre-request">Pre-Request</TabsTrigger>
                <TabsTrigger value="post-request">Post-Request</TabsTrigger>
              </TabsList>

              <div className="flex-1 min-h-0 mt-2">
                {/* Body Tab Content */}
                <TabsContent value="body" className="h-full m-0">
                  <div className="flex flex-col h-full gap-2">
                    <Select
                        value={currentModel.contentType}
                        onValueChange={(value) => setCurrentModel(prev => ({...prev, contentType: value}))}
                    >
                      <SelectTrigger>
                        <SelectValue placeholder="Content Type"/>
                      </SelectTrigger>
                      <SelectContent>
                        <SelectItem value="json">JSON</SelectItem>
                        <SelectItem value="xml">XML</SelectItem>
                        <SelectItem value="plaintext">Text/Plain</SelectItem>
                      </SelectContent>
                    </Select>
                    <div className="h-[calc(100%-40px)]">
                      <MonacoEditor
                          id={`request-body-${model.id}`}
                          value={currentModel.requestBody}
                          language={
                            currentModel.contentType
                          }
                          onChange={(newValue) => {
                            setCurrentModel(prev => ({
                              ...prev,
                              requestBody: newValue
                            }));
                          }}
                          height="full"
                      />
                    </div>
                  </div>
                </TabsContent>

                <TabsContent value="params" className="h-full m-0">
                  <PropertyTable
                      properties={currentModel.queryParams || []}
                      onChange={handleQueryParamsChange}
                  />
                </TabsContent>

                {/* Headers Tab Content */}
                <TabsContent value="headers" className="h-full m-0">
                  <PropertyTable
                      properties={currentModel.headers || []}
                      onChange={handleHeadersChange}
                  />
                </TabsContent>
                <TabsContent value="pre-request" className="h-full m-0">
                  <MonacoEditor
                      id={`pre-request-${model.id}`}
                      value={editorContents.preRequestScript}
                      language="javascript"
                      onChange={(value) => {
                        setEditorContents(prev => ({...prev, preRequestScript: value}));
                        setCurrentModel(prev => ({...prev, preRequestScript: value}));
                      }}
                      height="full"
                  />
                </TabsContent>

                {/* Post-Request Tab Content */}
                <TabsContent value="post-request" className="h-full m-0">
                  <MonacoEditor
                      id={`post-request-${model.id}`}
                      value={editorContents.postRequestScript}
                      language="javascript"
                      onChange={(value) => {
                        setEditorContents(prev => ({...prev, postRequestScript: value}));
                        setCurrentModel(prev => ({...prev, postRequestScript: value}));
                      }}
                      height="full"
                  />
                </TabsContent>
              </div>
            </Tabs>
          </div>

          {/* Response Section */}
          <div className="flex-1 min-h-0">
            <div className="flex items-center gap-2 mb-2">
              <span>Response</span>
              <span className="text-sm text-gray-500">{responseData.status}</span>
              <span className="text-sm text-gray-500">{responseData.time}</span>
              <span className="text-sm text-gray-500">{responseData.size}</span>
            </div>

            <Tabs value={currentResponseTab} onValueChange={setCurrentResponseTab} className="flex flex-col h-[calc(100%-2rem)]">
              <TabsList>
                <TabsTrigger value="response-body">Body</TabsTrigger>
                <TabsTrigger value="response-headers">Headers</TabsTrigger>
                <TabsTrigger value="console">Console</TabsTrigger>
              </TabsList>

              <div className="flex-1 min-h-0 mt-2">
                <TabsContent value="response-body" className="h-full m-0">
                  <MonacoEditor
                      id={`response-body-${model.id}`}
                      value={editorContents.responseBody}
                      readOnly={true}
                      height="full"
                  />
                </TabsContent>

                <TabsContent value="response-headers" className="h-full m-0">
                  {renderResponseHeaders()}
                </TabsContent>

                <TabsContent value="console" className="h-full m-0">
                  <MonacoEditor
                      id={`console-${model.id}`}
                      value={editorContents.consoleLog}
                      language="plaintext"
                      readOnly={true}
                      height="full"
                  />
                </TabsContent>
              </div>
            </Tabs>
          </div>
        </div>


      </div>
  );
};

export default HTTPClientView;
