import { useState, useCallback, useEffect } from 'react'
import { Button, Dialog, Input, Notification, toast } from '@/components/ui'
import Container from '@/components/shared/Container'
import AdaptableCard from '@/components/shared/AdaptableCard'
import { getDataSources } from '@/services/data-source.service'
import type { DataSourceDto } from '@/proxy/data-source'
import type {
  SqlFunctionDto,
  SqlQueryDto,
  SqlStoredProcedureDto,
  SqlViewDto,
  SqlObjectType,
  SqlQueryExecutionResultDto,
} from '@/proxy/sql-query-manager/models'
import {
  sqlFunctionService,
  sqlQueryService,
  sqlStoredProcedureService,
  sqlViewService,
} from '@/services/sql-query-manager.service'
import { FaDatabase, FaPlay, FaSave, FaSyncAlt } from 'react-icons/fa'
import { useLocalization } from '@/utils/hooks/useLocalization'
import SqlObjectExplorer from './components/SqlObjectExplorer'
import SqlEditor from './components/SqlEditor'
import SqlResultsGrid from './components/SqlResultsGrid'
import SqlObjectProperties from './components/SqlObjectProperties'
import { FaCloudUploadAlt } from 'react-icons/fa'

export type SqlObject = SqlFunctionDto | SqlQueryDto | SqlStoredProcedureDto | SqlViewDto

interface SqlManagerState {
  dataSources: DataSourceDto[]
  selectedDataSource: DataSourceDto | null
  selectedObject: SqlObject | null
  selectedObjectType: SqlObjectType | null
  editorContent: string
  isExecuting: boolean
  executionResult: SqlQueryExecutionResultDto | null
  showProperties: boolean
  isDirty: boolean
}

const SqlQueryManager = () => {
  const { translate } = useLocalization()

  const [state, setState] = useState<SqlManagerState>({
    dataSources: [],
    selectedDataSource: null,
    selectedObject: null,
    selectedObjectType: null,
    editorContent:
      '-- SQL Query Editor\n-- Write your SQL query here and press F5 or click Execute to run\n\nSELECT * FROM YourTable\nWHERE 1=1',
    isExecuting: false,
    executionResult: null,
    showProperties: false,
    isDirty: false,
  })

  const [showSaveDialog, setShowSaveDialog] = useState(false)
  const [saveDialogData, setSaveDialogData] = useState({ name: '', description: '' })
  const [showTemplateConfirmDialog, setShowTemplateConfirmDialog] = useState(false)
  const [pendingTemplate, setPendingTemplate] = useState<{ content: string; type: string } | null>(null)

  useEffect(() => {
    loadDataSources()
  }, [])

  const loadDataSources = async () => {
    try {
      const response = await getDataSources()
      const items = response.data.items || []
      if (items.length > 0) {
        setState((prev) => ({
          ...prev,
          dataSources: items,
          selectedDataSource: items[0],
        }))
      }
    } catch (error) {
      toast.push(
        <Notification type="danger" title={translate('::App.Platform.Error')}>
          {translate('::App.Platform.FailedtoloadDatasources')}
        </Notification>,
        { placement: 'top-center' },
      )
    }
  }

  const handleDataSourceChange = useCallback((dataSource: DataSourceDto) => {
    setState((prev) => ({
      ...prev,
      selectedDataSource: dataSource,
      selectedObject: null,
      editorContent: '',
      executionResult: null,
      isDirty: false,
    }))
  }, [])

  const handleObjectSelect = useCallback(
    (object: SqlObject | null, objectType: SqlObjectType | null) => {
      if (state.isDirty) {
        if (!confirm(translate('::App.Platform.UnsavedChangesConfirmation'))) {
          return
        }
      }

      let content = ''
      if (object) {
        if (objectType === 1) {
          // Query
          content = (object as SqlQueryDto).queryText
        } else if (objectType === 2) {
          // Stored Procedure
          content = (object as SqlStoredProcedureDto).procedureBody
        } else if (objectType === 3) {
          // View
          content = (object as SqlViewDto).viewDefinition
        } else if (objectType === 4) {
          // Function
          content = (object as SqlFunctionDto).functionBody
        }
      }

      setState((prev) => ({
        ...prev,
        selectedObject: object,
        selectedObjectType: objectType,
        editorContent: content,
        executionResult: null,
        isDirty: false,
      }))
    },
    [state.isDirty, translate],
  )

  const handleEditorChange = useCallback((value: string | undefined) => {
    setState((prev) => ({
      ...prev,
      editorContent: value || '',
      isDirty: true,
    }))
  }, [])

  const getTemplateContent = (templateType: string): string => {
    const templates: Record<string, string> = {
      'select': `-- Basic SELECT query
SELECT 
    Column1,
    Column2,
    Column3
FROM 
    TableName
WHERE 
    -- Add your conditions
    Column1 = 'value'
    AND IsActive = 1
ORDER BY 
    Column1 ASC;`,
      
      'insert': `-- Basic INSERT query
INSERT INTO TableName (Column1, Column2, Column3)
VALUES 
    ('Value1', 'Value2', 'Value3');`,
      
      'update': `-- Basic UPDATE query
UPDATE TableName
SET 
    Column1 = 'NewValue1',
    Column2 = 'NewValue2'
WHERE 
    -- Add your conditions
    Id = 1;`,
      
      'delete': `-- Basic DELETE query
DELETE FROM TableName
WHERE 
    -- Add your conditions
    Id = 1;`,
      
      'create-procedure': `-- Create Stored Procedure
CREATE PROCEDURE [dbo].[ProcedureName]
    @Parameter1 INT,
    @Parameter2 NVARCHAR(100)
AS
BEGIN
    SET NOCOUNT ON;
    
    -- Add your logic here
    SELECT 
        Column1,
        Column2
    FROM 
        TableName
    WHERE 
        Column1 = @Parameter1
        AND Column2 = @Parameter2;
END
GO`,
      
      'create-view': `-- Create View
CREATE VIEW [dbo].[ViewName]
AS
SELECT 
    t1.Column1,
    t1.Column2,
    t2.Column3
FROM 
    TableName1 t1
    INNER JOIN TableName2 t2 ON t1.Id = t2.TableName1Id
WHERE 
    t1.IsActive = 1;
GO`,
      
      'create-scalar-function': `-- Create Scalar Function
CREATE FUNCTION [dbo].[ScalarFunctionName]
(
    @Parameter1 INT,
    @Parameter2 NVARCHAR(100)
)
RETURNS NVARCHAR(200)
AS
BEGIN
    DECLARE @Result NVARCHAR(200);
    
    -- Add your logic here
    SELECT @Result = Column1 + ' ' + @Parameter2
    FROM TableName
    WHERE Id = @Parameter1;
    
    RETURN @Result;
END
GO`,
      
      'create-table-function': `-- Create Table-Valued Function
CREATE FUNCTION [dbo].[TableFunctionName]
(
    @Parameter1 INT,
    @Parameter2 NVARCHAR(100)
)
RETURNS TABLE
AS
RETURN
(
    SELECT 
        t.Column1,
        t.Column2,
        t.Column3,
        t.Column4
    FROM 
        TableName t
    WHERE 
        t.Id = @Parameter1
        AND t.Column2 LIKE '%' + @Parameter2 + '%'
        AND t.IsActive = 1
)
GO`
    }
    
    return templates[templateType] || templates['select']
  }

  const applyTemplate = useCallback((templateContent: string) => {
    setState((prev) => ({
      ...prev,
      editorContent: templateContent,
      selectedObject: null,
      selectedObjectType: null,
      executionResult: null,
      isDirty: false,
    }))

    toast.push(
      <Notification type="success" title={translate('::App.Platform.Success')}>
        {translate('::App.Platform.TemplateLoaded')}
      </Notification>,
      { placement: 'top-center' },
    )
  }, [translate])

  const handleTemplateSelect = useCallback((template: string, templateType: string) => {
    const templateContent = getTemplateContent(templateType)
    
    // Check if editor has content and it's not from a previous template
    const hasUserContent = state.editorContent.trim() && state.isDirty
    
    if (hasUserContent) {
      // Ask for confirmation
      setPendingTemplate({ content: templateContent, type: templateType })
      setShowTemplateConfirmDialog(true)
    } else {
      // Apply template directly
      applyTemplate(templateContent)
    }
  }, [translate, state.editorContent, state.isDirty, applyTemplate])

  const handleConfirmTemplateReplace = useCallback(() => {
    if (pendingTemplate) {
      applyTemplate(pendingTemplate.content)
    }
    setShowTemplateConfirmDialog(false)
    setPendingTemplate(null)
  }, [pendingTemplate, applyTemplate])

  const handleCancelTemplateReplace = useCallback(() => {
    setShowTemplateConfirmDialog(false)
    setPendingTemplate(null)
  }, [])

  const handleExecute = async () => {
    if (!state.selectedDataSource) {
      toast.push(
        <Notification type="warning" title={translate('::App.Platform.Warning')}>
          {translate('::App.Platform.PleaseSelectDataSource')}
        </Notification>,
        { placement: 'top-center' },
      )
      return
    }

    if (!state.editorContent.trim()) {
      toast.push(
        <Notification type="warning" title={translate('::App.Platform.Warning')}>
          {translate('::App.Platform.PleaseEnterQuery')}
        </Notification>,
        { placement: 'top-center' },
      )
      return
    }

    setState((prev) => ({ ...prev, isExecuting: true, executionResult: null }))

    try {
      const result = await sqlQueryService.executeQuery({
        queryText: state.editorContent,
        dataSourceCode: state.selectedDataSource.code || '',
      })

      setState((prev) => ({ ...prev, executionResult: result.data, isExecuting: false }))

      toast.push(
        <Notification type="success" title={translate('::App.Platform.Success')}>
          {translate('::App.Platform.QueryExecutedSuccessfully')} ({result.data.executionTimeMs}ms)
        </Notification>,
        { placement: 'top-center' },
      )
    } catch (error: any) {
      setState((prev) => ({ ...prev, isExecuting: false }))
      toast.push(
        <Notification type="danger" title={translate('::App.Platform.Error')}>
          {error.response?.data?.error?.message || translate('::App.Platform.FailedToExecuteQuery')}
        </Notification>,
        { placement: 'top-center' },
      )
    }
  }

  const handleSave = async () => {
    if (!state.selectedDataSource) {
      toast.push(
        <Notification type="warning" title={translate('::App.Platform.Warning')}>
          {translate('::App.Platform.PleaseSelectDataSource')}
        </Notification>,
        { placement: 'top-center' },
      )
      return
    }

    if (!state.editorContent.trim()) {
      toast.push(
        <Notification type="warning" title={translate('::App.Platform.Warning')}>
          {translate('::App.Platform.PleaseEnterContentToSave')}
        </Notification>,
        { placement: 'top-center' },
      )
      return
    }

    if (state.selectedObject && state.selectedObjectType) {
      // Update existing object
      await handleUpdate()
    } else {
      // Create new object - show dialog to choose type
      setSaveDialogData({ name: '', description: '' })
      setShowSaveDialog(true)
    }
  }

  const handleUpdate = async () => {
    if (!state.selectedObject || !state.selectedObjectType || !state.selectedDataSource) return
    if (!state.selectedObject.id) return

    try {
      const objectId = state.selectedObject.id

      switch (state.selectedObjectType) {
        case 1: // Query
          await sqlQueryService.update(objectId, {
            ...(state.selectedObject as SqlQueryDto),
            queryText: state.editorContent,
          })
          break
        case 2: // Stored Procedure
          await sqlStoredProcedureService.update(objectId, {
            displayName: (state.selectedObject as SqlStoredProcedureDto).displayName,
            description: (state.selectedObject as SqlStoredProcedureDto).description,
            procedureBody: state.editorContent,
            category: (state.selectedObject as SqlStoredProcedureDto).category,
            parameters: (state.selectedObject as SqlStoredProcedureDto).parameters,
          })
          break
        case 3: // View
          await sqlViewService.update(objectId, {
            displayName: (state.selectedObject as SqlViewDto).displayName,
            description: (state.selectedObject as SqlViewDto).description,
            viewDefinition: state.editorContent,
            category: (state.selectedObject as SqlViewDto).category,
            withSchemaBinding: (state.selectedObject as SqlViewDto).withSchemaBinding,
          })
          break
        case 4: // Function
          await sqlFunctionService.update(objectId, {
            displayName: (state.selectedObject as SqlFunctionDto).displayName,
            description: (state.selectedObject as SqlFunctionDto).description,
            functionBody: state.editorContent,
            returnType: (state.selectedObject as SqlFunctionDto).returnType,
            category: (state.selectedObject as SqlFunctionDto).category,
            parameters: (state.selectedObject as SqlFunctionDto).parameters,
          })
          break
      }

      setState((prev) => ({ ...prev, isDirty: false }))

      toast.push(
        <Notification type="success" title={translate('::App.Platform.Success')}>
          {translate('::App.Platform.ObjectUpdatedSuccessfully')}
        </Notification>,
        { placement: 'top-center' },
      )
    } catch (error: any) {
      toast.push(
        <Notification type="danger" title={translate('::App.Platform.Error')}>
          {error.response?.data?.error?.message || translate('::App.Platform.FailedToUpdateObject')}
        </Notification>,
        { placement: 'top-center' },
      )
    }
  }

  const handleCreateNewQuery = async () => {
    if (!state.selectedDataSource || !saveDialogData.name) return

    try {
      await sqlQueryService.create({
        code: saveDialogData.name.replace(/\s+/g, '_'),
        name: saveDialogData.name,
        description: saveDialogData.description,
        queryText: state.editorContent,
        dataSourceCode: state.selectedDataSource.code || '',
        category: '',
        tags: '',
        isModifyingData: false,
        parameters: '',
      })

      setState((prev) => ({ ...prev, isDirty: false }))
      setShowSaveDialog(false)

      toast.push(
        <Notification type="success" title={translate('::App.Platform.Success')}>
          {translate('::App.Platform.QuerySavedSuccessfully')}
        </Notification>,
        { placement: 'top-center' },
      )
    } catch (error: any) {
      toast.push(
        <Notification type="danger" title={translate('::App.Platform.Error')}>
          {error.response?.data?.error?.message || translate('::App.Platform.FailedToSaveQuery')}
        </Notification>,
        { placement: 'top-center' },
      )
    }
  }

  const handleDeploy = async () => {
    if (!state.selectedObject || !state.selectedObjectType) {
      toast.push(
        <Notification type="warning" title={translate('::App.Platform.Warning')}>
          {translate('::App.Platform.PleaseSelectAnObjectToDeploy')}
        </Notification>,
        { placement: 'top-center' },
      )
      return
    }
    if (!state.selectedObject.id) return

    try {
      const objectId = state.selectedObject.id
      let result: any

      switch (state.selectedObjectType) {
        case 2: // Stored Procedure
          result = await sqlStoredProcedureService.deploy({ id: objectId, dropIfExists: true })
          break
        case 3: // View
          result = await sqlViewService.deploy({ id: objectId, dropIfExists: true })
          break
        case 4: // Function
          result = await sqlFunctionService.deploy({ id: objectId, dropIfExists: true })
          break
        default:
          toast.push(
            <Notification type="warning" title={translate('::App.Platform.Warning')}>
              {translate('::App.Platform.ThisObjectTypeCannotBeDeployed')}
            </Notification>,
            { placement: 'top-center' },
          )
          return
      }

      toast.push(
        <Notification type="success" title={translate('::App.Platform.Success')}>
          {translate('::App.Platform.ObjectDeployedSuccessfully')}
        </Notification>,
        { placement: 'top-center' },
      )
    } catch (error: any) {
      toast.push(
        <Notification type="danger" title={translate('::App.Platform.Error')}>
          {error.response?.data?.error?.message || translate('::App.Platform.FailedToDeployObject')}
        </Notification>,
        { placement: 'top-center' },
      )
    }
  }

  return (
    <Container className="h-full overflow-hidden">
      <div className="flex flex-col h-full gap-4 p-1">
        {/* Toolbar */}
        <AdaptableCard className="flex-shrink-0 shadow-sm">
          <div className="flex items-center justify-between px-1 py-1">
            <div className="flex items-center gap-3">
              <FaDatabase className="text-lg text-blue-500" />
              <span className="text-sm font-medium text-gray-600 dark:text-gray-400">
                {translate('::App.Platform.DataSource')}:
              </span>
              <select
                className="border border-gray-300 rounded px-1 py-1"
                value={state.selectedDataSource?.code || ''}
                onChange={(e) => {
                  const ds = state.dataSources.find((d) => d.code === e.target.value)
                  if (ds) handleDataSourceChange(ds)
                }}
              >
                {state.dataSources.map((ds) => (
                  <option key={ds.code} value={ds.code}>
                    {ds.code}
                  </option>
                ))}
              </select>
            </div>

            <div className="flex items-center gap-3">
              <Button
                size="sm"
                variant="solid"
                color="blue-600"
                icon={<FaPlay />}
                onClick={handleExecute}
                loading={state.isExecuting}
                disabled={!state.selectedDataSource}
                className="shadow-sm"
              >
                {translate('::App.Platform.Execute')}
                <span className="ml-1 text-xs opacity-75">(F5)</span>
              </Button>
              <Button
                size="sm"
                variant="solid"
                icon={<FaSave />}
                onClick={handleSave}
                disabled={!state.isDirty || !state.selectedDataSource}
                className="shadow-sm"
              >
                {translate('::App.Platform.Save')}
                <span className="ml-1 text-xs opacity-75">(Ctrl+S)</span>
              </Button>
              {state.selectedObject &&
                state.selectedObjectType &&
                state.selectedObjectType !== 1 && (
                  <Button
                    size="sm"
                    variant="solid"
                    icon={<FaCloudUploadAlt />}
                    onClick={handleDeploy}
                    disabled={!state.selectedDataSource}
                    className="shadow-sm"
                  >
                    {translate('::App.Platform.Deploy')}
                  </Button>
                )}
              <Button
                size="sm"
                variant="twoTone"
                icon={<FaSyncAlt />}
                onClick={() => window.location.reload()}
                className="shadow-sm"
              >
                {translate('::App.Platform.Refresh')}
              </Button>
            </div>
          </div>
        </AdaptableCard>

        {/* Main Content Area */}
        <div className="flex-1 flex gap-4 min-h-0">
          {/* Left Panel - Object Explorer */}
          <div className="w-80 flex-shrink-0 flex flex-col min-h-0">
            <AdaptableCard className="h-full" bodyClass="p-0">
              <div className="h-full flex flex-col">
                <div className="border-b px-4 py-3 bg-gray-50 dark:bg-gray-800 flex-shrink-0">
                  <h6 className="font-semibold text-sm">
                    {translate('::App.Platform.ObjectExplorer')}
                  </h6>
                </div>
                <div className="flex-1 overflow-auto p-2 min-h-0">
                  <SqlObjectExplorer
                    dataSource={state.selectedDataSource}
                    onObjectSelect={handleObjectSelect}
                    selectedObject={state.selectedObject}
                    onTemplateSelect={handleTemplateSelect}
                  />
                </div>
              </div>
            </AdaptableCard>
          </div>

          {/* Center Panel - Editor and Results */}
          <div className="flex-1 flex flex-col min-h-0">
            <div className="flex-1 border rounded-lg shadow-sm bg-white dark:bg-gray-800 flex flex-col overflow-hidden">
              <div className="border-b px-4 py-2 bg-gray-50 dark:bg-gray-800 flex-shrink-0">
                <h6 className="font-semibold text-sm">{translate('::App.Platform.QueryEditor')}</h6>
              </div>
              <div className="flex-1 min-h-0">
                <SqlEditor
                  value={state.editorContent}
                  onChange={handleEditorChange}
                  onExecute={handleExecute}
                  onSave={handleSave}
                  readOnly={state.isExecuting}
                />
              </div>
            </div>

            {state.executionResult && (
              <div className="flex-1 mt-4 border rounded-lg shadow-sm bg-white dark:bg-gray-800 flex flex-col overflow-hidden">
                <div className="border-b px-4 py-2 bg-gray-50 dark:bg-gray-800 flex-shrink-0">
                  <h6 className="font-semibold text-sm">{translate('::App.Platform.Results')}</h6>
                </div>
                <div className="flex-1 overflow-hidden min-h-0">
                  <SqlResultsGrid result={state.executionResult} />
                </div>
              </div>
            )}
          </div>

          {/* Right Panel - Properties (Optional) */}
          {state.showProperties && state.selectedObject && (
            <div className="w-80 flex-shrink-0 flex flex-col min-h-0">
              <SqlObjectProperties object={state.selectedObject} type={state.selectedObjectType} />
            </div>
          )}
        </div>
      </div>

      {/* Template Confirmation Dialog */}
      <Dialog
        isOpen={showTemplateConfirmDialog}
        onClose={handleCancelTemplateReplace}
        onRequestClose={handleCancelTemplateReplace}
      >
        <h5 className="mb-4">{translate('::App.Platform.ConfirmTemplateReplace')}</h5>
        <p className="mb-6 text-gray-600 dark:text-gray-400">
          {translate('::App.Platform.TemplateReplaceWarning')}
        </p>
        <div className="flex justify-end gap-2">
          <Button variant="plain" onClick={handleCancelTemplateReplace}>
            {translate('::App.Platform.Cancel')}
          </Button>
          <Button variant="solid" onClick={handleConfirmTemplateReplace}>
            {translate('::App.Platform.Replace')}
          </Button>
        </div>
      </Dialog>

      {/* Save Dialog */}
      <Dialog
        isOpen={showSaveDialog}
        onClose={() => setShowSaveDialog(false)}
        onRequestClose={() => setShowSaveDialog(false)}
      >
        <h5 className="mb-4">{translate('::App.Platform.SaveAsNewQuery')}</h5>
        <div className="space-y-4">
          <div>
            <label className="block mb-2">{translate('::App.Platform.Name')}</label>
            <Input
              value={saveDialogData.name}
              onChange={(e) => setSaveDialogData((prev) => ({ ...prev, name: e.target.value }))}
            />
          </div>
          <div>
            <label className="block mb-2">{translate('::App.Platform.Description')}</label>
            <Input
              value={saveDialogData.description}
              onChange={(e) =>
                setSaveDialogData((prev) => ({ ...prev, description: e.target.value }))
              }
            />
          </div>
          <div className="flex justify-end gap-2">
            <Button variant="plain" onClick={() => setShowSaveDialog(false)}>
              {translate('::App.Platform.Cancel')}
            </Button>
            <Button variant="solid" onClick={handleCreateNewQuery}>
              {translate('::App.Platform.Save')}
            </Button>
          </div>
        </div>
      </Dialog>
    </Container>
  )
}

export default SqlQueryManager
