import React, { useState, useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { DataProvider, useReportData } from './DataContext';
import { BandProvider } from './BandContext';
import Toolbar from './Toolbar';
import EditorCanvas from './EditorCanvas';
import CharacterPalette from './CharacterPalette';
import ObjectInspector from './ObjectInspector';
import { useNomenclatureData } from '../../contexts/NomenclatureDataContext';
import api from '../../services/api';
import './ReportEditor.css';

function ReportEditorContent() {
  const [report, setReport] = useState({
    name: 'Untitled Report',
    pageWidth: 80,
    pageHeight: 66,
    apiEndpoint: '',
    elements: []
  });

  const [selectedElementIds, setSelectedElementIds] = useState([]);
  const [toolMode, setToolMode] = useState('select');
  const [borderStyle, setBorderStyle] = useState('single');
  const [previewMode, setPreviewMode] = useState(false);
  const [selectedChar, setSelectedChar] = useState('─');
  const [showCharacterPalette, setShowCharacterPalette] = useState(false);

  // Save/Load state
  const [reportId, setReportId] = useState(null);
  const [isSaving, setIsSaving] = useState(false);
  const [showLoadDialog, setShowLoadDialog] = useState(false);
  const [savedReports, setSavedReports] = useState([]);
  const [loadingReports, setLoadingReports] = useState(false);

  // Auto-load report and vehicle data passed via router state
  const location = useLocation();
  const { setData } = useReportData();
  const { definitions, entries, isLoaded } = useNomenclatureData();

  useEffect(() => {
    const { reportName, vehicleData } = location.state || {};
    if (!reportName) return;

    api.get('/api/reports/').then(res => {
      const reports = res.data.results || res.data;
      const found = reports.find(r => r.name === reportName);
      if (found) {
        setReport({
          name: found.name,
          pageWidth: found.page_width,
          pageHeight: found.page_height,
          apiEndpoint: found.api_endpoint || '',
          elements: found.elements || [],
        });
        setReportId(found.id);
      } else {
        // Report doesn't exist yet — pre-fill the name so Save creates it
        setReport(prev => ({ ...prev, name: reportName }));
      }
      if (vehicleData) {
        setData(vehicleData);
      }
    }).catch(err => {
      console.error('Failed to auto-load report:', err);
    });
  }, []);

  // When no vehicle data was passed (direct navigation), auto-set sample data
  // once nomenclatures have loaded so field bindings can be designed
  useEffect(() => {
    if (!isLoaded || location.state?.vehicleData) return;

    const extra = {};
    for (const def of Object.values(definitions)) {
      if (def.kind === 'lookup') {
        const activeEntries = (entries[def.code] || []).filter(e => e.is_active);
        const firstEntry = activeEntries[0];
        if (firstEntry?.data && Object.keys(firstEntry.data).length > 0) {
          extra[def.name] = { ...firstEntry.data };
        } else if (def.fields?.length > 0) {
          const sample = {};
          for (const field of def.fields) {
            if (field.field_type === 'number') sample[field.key] = 0;
            else if (field.field_type === 'bool') sample[field.key] = false;
            else sample[field.key] = 'Sample';
          }
          extra[def.name] = sample;
        } else {
          extra[def.name] = {};
        }
      } else {
        extra[def.name] = 'Sample Text';
      }
    }

    setData({
      vehicle: {
        vehicle_number: 'АА1234ВВ',
        trailer1_number: 'ПВ5678ВВ',
        trailer2_number: null,
        driver_pid: '123456789',
        tare: 8500,
        tare_date: '2026-02-22T08:00:00Z',
        tare_user_name: 'operator',
        gross: 28500,
        gross_date: '2026-02-22T10:30:00Z',
        gross_user_name: 'operator',
        net: 20000,
        net_date: '2026-02-22T10:30:00Z',
        net_user_name: 'operator',
        doc_number: '2026-001',
        extra,
      }
    });
  }, [isLoaded]);

  const handleAddElement = (element) => {
    setReport(prev => {
      // Check if the new element is positioned inside a band
      const containingBand = prev.elements.find(el => {
        if (el.type !== 'band') return false;
        // Check if element is within band's Y range
        const bandMinY = el.y;
        const bandMaxY = el.y + el.height - 1;
        const elementY = element.y;
        return elementY >= bandMinY && elementY <= bandMaxY;
      });

      // Adjust element position to be relative to band if inside one
      let adjustedElement = { ...element };
      if (containingBand) {
        adjustedElement.y = element.y - containingBand.y;
      }

      let updatedElements = [...prev.elements, adjustedElement];

      // If inside a band, add element ID to band's children array
      if (containingBand) {
        updatedElements = updatedElements.map(el => {
          if (el.id === containingBand.id) {
            return {
              ...el,
              children: [...(el.children || []), adjustedElement.id]
            };
          }
          return el;
        });
      }

      return {
        ...prev,
        elements: updatedElements
      };
    });

    setSelectedElementIds([element.id]);
    // After adding an element, switch back to select mode (unless in drawTable mode)
    if (toolMode !== 'drawTable') {
      setToolMode('select');
    }
  };

  const handleElementUpdate = (elementId, updates) => {
    setReport(prev => {
      const element = prev.elements.find(el => el.id === elementId);

      // Check if this is a band height change
      if (element && element.type === 'band' && updates.height !== undefined && updates.height !== element.height) {
        const heightDelta = updates.height - element.height;
        const bandMaxY = element.y + element.height - 1;

        // Shift all elements (including other bands) below this band
        return {
          ...prev,
          elements: prev.elements.map(el => {
            if (el.id === elementId) {
              // Apply updates to the band itself
              return { ...el, ...updates };
            }
            // Shift elements that are below the band (not children of the band)
            const isChildOfThisBand = element.children && element.children.includes(el.id);
            if (!isChildOfThisBand && el.y > bandMaxY) {
              return { ...el, y: el.y + heightDelta };
            }
            return el;
          })
        };
      }

      // Normal update (not a band height change)
      return {
        ...prev,
        elements: prev.elements.map(el =>
          el.id === elementId ? { ...el, ...updates } : el
        )
      };
    });
  };

  const handleElementDelete = (elementId) => {
    setReport(prev => ({
      ...prev,
      elements: prev.elements.filter(el => el.id !== elementId)
    }));
    setSelectedElementIds(prev => prev.filter(id => id !== elementId));
  };

  const handleDeleteSelected = () => {
    setReport(prev => ({
      ...prev,
      elements: prev.elements.filter(el => !selectedElementIds.includes(el.id))
    }));
    setSelectedElementIds([]);
  };

  const handleSelectElement = (elementId, addToSelection = false) => {
    if (addToSelection) {
      setSelectedElementIds(prev => {
        if (prev.includes(elementId)) {
          return prev.filter(id => id !== elementId);
        } else {
          return [...prev, elementId];
        }
      });
    } else {
      // If clicking on an already-selected element in a multi-selection, keep the multi-selection
      // This allows dragging the entire selection
      setSelectedElementIds(prev => {
        if (prev.length > 1 && prev.includes(elementId)) {
          return prev; // Keep existing multi-selection
        }
        return [elementId]; // Otherwise, select just this element
      });
    }
  };

  const handleSelectMultiple = (elementIds) => {
    setSelectedElementIds(elementIds);
  };

  const handleDeselectAll = () => {
    setSelectedElementIds([]);
  };

  const handleToolChange = (newTool) => {
    setToolMode(newTool);
    // Deselect when changing tools (except for drawTable)
    if (newTool !== 'select' && newTool !== 'drawTable') {
      setSelectedElementIds([]);
    }
    // Show/hide character palette for drawTable mode
    if (newTool === 'drawTable') {
      setShowCharacterPalette(true);
    } else {
      setShowCharacterPalette(false);
    }
  };

  const handleTogglePreview = () => {
    setPreviewMode(prev => !prev);
  };

  const handleApiEndpointChange = (endpoint) => {
    setReport(prev => ({
      ...prev,
      apiEndpoint: endpoint
    }));
  };

  const handleReportNameChange = (name) => {
    setReport(prev => ({ ...prev, name }));
  };

  // Save report to backend
  const handleSave = async () => {
    if (!report.name.trim()) {
      alert('Please enter a report name');
      return;
    }

    setIsSaving(true);
    try {
      const payload = {
        name: report.name,
        page_width: report.pageWidth,
        page_height: report.pageHeight,
        api_endpoint: report.apiEndpoint,
        elements: report.elements
      };

      if (reportId) {
        // Update existing report
        await api.put(`/api/reports/${reportId}/`, payload);
      } else {
        // Create new report
        const res = await api.post('/api/reports/', payload);
        setReportId(res.data.id);
      }
      alert('Report saved successfully');
    } catch (err) {
      console.error('Failed to save report:', err);
      alert('Failed to save report: ' + (err.response?.data?.detail || err.message));
    } finally {
      setIsSaving(false);
    }
  };

  // Load reports list for dialog
  const handleLoadClick = async () => {
    setLoadingReports(true);
    setShowLoadDialog(true);
    try {
      const res = await api.get('/api/reports/');
      setSavedReports(res.data.results || res.data || []);
    } catch (err) {
      console.error('Failed to load reports list:', err);
      alert('Failed to load reports list');
    } finally {
      setLoadingReports(false);
    }
  };

  // Load a specific report
  const handleLoadReport = async (id) => {
    try {
      const res = await api.get(`/api/reports/${id}/`);
      const data = res.data;
      setReport({
        name: data.name,
        pageWidth: data.page_width,
        pageHeight: data.page_height,
        apiEndpoint: data.api_endpoint || '',
        elements: data.elements || []
      });
      setReportId(data.id);
      setSelectedElementIds([]);
      setShowLoadDialog(false);
    } catch (err) {
      console.error('Failed to load report:', err);
      alert('Failed to load report');
    }
  };

  // Delete a report
  const handleDeleteReport = async (id) => {
    if (!window.confirm('Are you sure you want to delete this report?')) return;
    try {
      await api.delete(`/api/reports/${id}/`);
      setSavedReports(prev => prev.filter(r => r.id !== id));
      if (reportId === id) {
        setReportId(null);
      }
    } catch (err) {
      console.error('Failed to delete report:', err);
      alert('Failed to delete report');
    }
  };

  // New report
  const handleNewReport = () => {
    if (report.elements.length > 0) {
      if (!window.confirm('Discard current report and create a new one?')) return;
    }
    setReport({
      name: 'Untitled Report',
      pageWidth: 80,
      pageHeight: 66,
      apiEndpoint: '',
      elements: []
    });
    setReportId(null);
    setSelectedElementIds([]);
    setShowLoadDialog(false);
  };

  // Handle keyboard shortcuts
  useEffect(() => {
    const handleKeyDown = (e) => {
      if (e.key === 'Escape') {
        setSelectedElementIds([]);
        setToolMode('select');
        setShowCharacterPalette(false);
      } else if (e.key.toLowerCase() === 'd' && !e.ctrlKey && !e.metaKey && e.target.tagName !== 'INPUT') {
        handleToolChange('drawTable');
      } else if (e.key === 'Delete' && selectedElementIds.length > 0) {
        handleDeleteSelected();
      } else if (e.key.toLowerCase() === 'a' && (e.ctrlKey || e.metaKey) && toolMode === 'select') {
        e.preventDefault();
        setSelectedElementIds(report.elements.map(el => el.id));
      }
    };

    document.addEventListener('keydown', handleKeyDown);
    return () => document.removeEventListener('keydown', handleKeyDown);
  }, [selectedElementIds, toolMode, report.elements]);

  // Get the selected element for the Object Inspector
  const selectedElement = selectedElementIds.length === 1
    ? report.elements.find(el => el.id === selectedElementIds[0])
    : null;

  return (
    <div className="report-editor">
      <Toolbar
        toolMode={toolMode}
        onToolChange={handleToolChange}
        borderStyle={borderStyle}
        onBorderStyleChange={setBorderStyle}
        previewMode={previewMode}
        onTogglePreview={handleTogglePreview}
        onSave={handleSave}
        onLoad={handleLoadClick}
        reportName={report.name}
        onReportNameChange={handleReportNameChange}
        isSaving={isSaving}
      />
      <div className="editor-layout">
        <EditorCanvas
          elements={report.elements}
          selectedElementIds={selectedElementIds}
          onElementSelect={handleSelectElement}
          onSelectMultiple={handleSelectMultiple}
          onDeselectAll={handleDeselectAll}
          onElementUpdate={handleElementUpdate}
          onElementDelete={handleElementDelete}
          toolMode={toolMode}
          borderStyle={borderStyle}
          onAddElement={handleAddElement}
          previewMode={previewMode}
          selectedChar={selectedChar}
        />
      </div>
      {selectedElementIds.length === 1 && (
        <ObjectInspector
          element={selectedElement}
          allElements={report.elements}
          onUpdate={(updates) => handleElementUpdate(selectedElementIds[0], updates)}
        />
      )}
      {showCharacterPalette && (
        <CharacterPalette
          selectedChar={selectedChar}
          onSelectChar={setSelectedChar}
          onClose={() => {
            setShowCharacterPalette(false);
            setToolMode('select');
          }}
        />
      )}

      {/* Load Report Dialog */}
      {showLoadDialog && (
        <div className="load-dialog-overlay" onClick={() => setShowLoadDialog(false)}>
          <div className="load-dialog" onClick={e => e.stopPropagation()}>
            <div className="load-dialog-header">
              <h2>Load Report</h2>
              <button className="load-dialog-close" onClick={() => setShowLoadDialog(false)}>×</button>
            </div>
            <div className="load-dialog-actions">
              <button className="load-dialog-new-btn" onClick={handleNewReport}>
                + New Report
              </button>
            </div>
            <div className="load-dialog-content">
              {loadingReports ? (
                <div className="load-dialog-loading">Loading...</div>
              ) : savedReports.length === 0 ? (
                <div className="load-dialog-empty">No saved reports</div>
              ) : (
                <ul className="load-dialog-list">
                  {savedReports.map(r => (
                    <li
                      key={r.id}
                      className={`load-dialog-item ${reportId === r.id ? 'load-dialog-item--current' : ''}`}
                    >
                      <div className="load-dialog-item-info" onClick={() => handleLoadReport(r.id)}>
                        <span className="load-dialog-item-name">{r.name}</span>
                        <span className="load-dialog-item-date">
                          {new Date(r.updated_at).toLocaleDateString()}
                        </span>
                      </div>
                      <button
                        className="load-dialog-item-delete"
                        onClick={() => handleDeleteReport(r.id)}
                        title="Delete report"
                      >
                        🗑
                      </button>
                    </li>
                  ))}
                </ul>
              )}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

function ReportEditor() {
  return (
    <DataProvider>
      <BandProvider>
        <ReportEditorContent />
      </BandProvider>
    </DataProvider>
  );
}

export default ReportEditor;
