import { useState } from 'react';
import { useLanguage } from '../../../providers/language/LanguageContext';
import styles from '../ContentPreview.module.css';

interface JsonRendererProps {
  previewContent: string;
  fileName: string;
}

export function JsonRenderer({ previewContent, fileName }: JsonRendererProps) {
  const { t } = useLanguage();
  const [collapsedRows, setCollapsedRows] = useState<Set<string>>(new Set());

  const handleCopyJson = () => {
    try {
      const parsedJson = JSON.parse(previewContent);
      const formattedJson = JSON.stringify(parsedJson, null, 2);
      navigator.clipboard.writeText(formattedJson);
    } catch (error) {
      navigator.clipboard.writeText(previewContent);
    }
  };

  const formatTimestamp = (value: string | number): string => {
    const numValue = typeof value === 'string' ? parseFloat(value) : value;
    
    if (!isNaN(numValue) && numValue > 1000000000 && numValue < 4102444800) {
      const date = new Date(numValue * 1000);
      if (!isNaN(date.getTime())) {
        return date.toLocaleString('en-US', {
          year: 'numeric',
          month: '2-digit',
          day: '2-digit',
          hour: '2-digit',
          minute: '2-digit',
          second: '2-digit',
          hour12: false
        });
      }
    }
    
    return String(value);
  };

  const preprocessJson = (obj: any, parentKey = ''): {keys: string[], values: any[], types: (string | 'timestamp')[], isNested: boolean[]} => {
    const keys: string[] = [];
    const values: any[] = [];
    const types: (string | 'timestamp')[] = [];
    const isNested: boolean[] = [];
    
    if (obj === null || obj === undefined) {
      keys.push(parentKey);
      values.push(String(obj));
      types.push(typeof obj);
      isNested.push(false);
    } else if (typeof obj === 'boolean' || typeof obj === 'number') {
      keys.push(parentKey);
      if (typeof obj === 'number' && (parentKey.toLowerCase().includes('timestamp') || parentKey.toLowerCase().includes('time'))) {
        values.push(formatTimestamp(obj));
        types.push('timestamp');
      } else {
        values.push(obj);
        types.push(typeof obj);
      }
      isNested.push(false);
    } else if (typeof obj === 'string') {
      keys.push(parentKey);
      const numValue = parseFloat(obj);
      if (!isNaN(numValue) && (parentKey.toLowerCase().includes('timestamp') || parentKey.toLowerCase().includes('time'))) {
        values.push(formatTimestamp(obj));
        types.push('timestamp');
      } else {
        try {
          const parsedString = JSON.parse(obj);
          if (typeof parsedString === 'object' && parsedString !== null) {
            // For stringified JSON objects, process them recursively
            const nestedData = preprocessJson(parsedString, '');
            values.push(nestedData);
            types.push(Array.isArray(parsedString) ? 'array' : 'object');
            isNested.push(true);
          } else {
            values.push(obj);
            types.push('string');
            isNested.push(false);
          }
        } catch (e) {
          values.push(obj);
          types.push('string');
          isNested.push(false);
        }
      }
    } else if (Array.isArray(obj)) {
      if (obj.length === 0) {
        keys.push(parentKey);
        values.push('');
        types.push('array');
        isNested.push(false);
      } else {
        const allPrimitive = obj.every(item => 
          item === null || 
          typeof item !== 'object' || 
          (typeof item === 'object' && !Array.isArray(item) && Object.keys(item).length === 0)
        );
        
        if (allPrimitive) {
          if (parentKey) {
            keys.push(parentKey);
            values.push({
              isArray: true,
              items: obj,
              length: obj.length
            });
            types.push('array');
            isNested.push(true);
          } else {
            // For root-level arrays, always use compact array display
            keys.push('');
            values.push({
              isArray: true,
              items: obj,
              length: obj.length
            });
            types.push('array');
            isNested.push(true);
          }
        } else {
          const nestedKeys: string[] = [];
          const nestedValues: any[] = [];
          const nestedTypes: (string | 'timestamp')[] = [];
          const nestedIsNested: boolean[] = [];
          
          obj.forEach((item, index) => {
            if (typeof item === 'object' && item !== null) {
              const nestedData = preprocessJson(item, `Item ${index + 1}`);
              nestedKeys.push(...nestedData.keys);
              nestedValues.push(...nestedData.values);
              nestedTypes.push(...nestedData.types);
              nestedIsNested.push(...nestedData.isNested);
            } else {
              nestedKeys.push(`Item ${index + 1}`);
              nestedValues.push(String(item));
              nestedTypes.push(typeof item);
              nestedIsNested.push(false);
            }
          });
          
          if (parentKey) {
            keys.push(parentKey);
            values.push({
              keys: nestedKeys,
              values: nestedValues,
              types: nestedTypes,
              isNested: nestedIsNested
            });
            types.push('array');
            isNested.push(true);
          } else {
            keys.push(...nestedKeys);
            values.push(...nestedValues);
            types.push(...nestedTypes);
            isNested.push(...nestedIsNested);
          }
        }
      }
    } else if (typeof obj === 'object') {
      const entries = Object.entries(obj);
      if (entries.length === 0) {
        keys.push(parentKey);
        values.push('{}');
        types.push('object');
        isNested.push(false);
      } else {
        const nestedKeys: string[] = [];
        const nestedValues: any[] = [];
        const nestedTypes: (string | 'timestamp')[] = [];
        const nestedIsNested: boolean[] = [];
        
        entries.forEach(([key, value]) => {
          if (typeof value === 'object' && value !== null) {
            const nestedData = preprocessJson(value, key);
            nestedKeys.push(...nestedData.keys);
            nestedValues.push(...nestedData.values);
            nestedTypes.push(...nestedData.types);
            nestedIsNested.push(...nestedData.isNested);
          } else {
            let processedValue = value;
            let processedType: string | 'timestamp' = typeof value;
            
            if (typeof value === 'number' && (key.toLowerCase().includes('timestamp') || key.toLowerCase().includes('time'))) {
              processedValue = formatTimestamp(value);
              processedType = 'timestamp';
            } else if (typeof value === 'string') {
              const numValue = parseFloat(value);
              if (!isNaN(numValue) && (key.toLowerCase().includes('timestamp') || key.toLowerCase().includes('time'))) {
                processedValue = formatTimestamp(value);
                processedType = 'timestamp';
              }
            }
            
            nestedKeys.push(key);
            nestedValues.push(processedValue);
            nestedTypes.push(processedType);
            nestedIsNested.push(false);
          }
        });

        if (parentKey) {
          keys.push(parentKey);
          values.push({
            keys: nestedKeys,
            values: nestedValues,
            types: nestedTypes,
            isNested: nestedIsNested
          });
          types.push('object');
          isNested.push(true);
        } else {
          keys.push(...nestedKeys);
          values.push(...nestedValues);
          types.push(...nestedTypes);
          isNested.push(...nestedIsNested);
        }
      }
    }
    
    return { keys, values, types, isNested };
  };

  const renderTable = (data: {keys: string[], values: any[], types: (string | 'timestamp')[], isNested: boolean[]}, level = 0, parentPath = '') => {
    if (!data || data.keys.length === 0) return null;
    
    const toggleCollapse = (rowPath: string) => {
      const newCollapsed = new Set(collapsedRows);
      if (newCollapsed.has(rowPath)) {
        newCollapsed.delete(rowPath);
      } else {
        newCollapsed.add(rowPath);
      }
      setCollapsedRows(newCollapsed);
    };
    
    const isLongContent = (value: any, type: string): boolean => {
      if (typeof value === 'string') {
        return value.includes('\n') || value.length > 80;
      }
      if (type === 'array' && Array.isArray(value)) {
        return value.length > 8;
      }
      if (typeof value === 'object' && value !== null && 'keys' in value) {
        return value.keys.length > 1;
      }
      if (typeof value === 'object' && value !== null && 'isArray' in value) {
        return value.length > 8;
      }
      return false;
    };
    
     const getPreview = (value: any, type: string): string => {
       if (typeof value === 'string') {
         if (value.includes('\n')) {
           const firstLine = value.split('\n')[0];
           return firstLine.length > 60 ? firstLine.substring(0, 60) + '...' : firstLine + '...';
         }
         if (value.length > 80) {
           return value.substring(0, 80) + '...';
         }
         return value;
       }
       if (type === 'array' && Array.isArray(value)) {
         return `[${value.slice(0, 3).map(item => typeof item === 'string' ? `"${item}"` : String(item)).join(', ')}${value.length > 3 ? '...' : ''}]`;
       }
       if (typeof value === 'object' && value !== null && 'isArray' in value) {
         return `[${value.items.slice(0, 3).map((item: any) => typeof item === 'string' ? `"${item}"` : String(item)).join(', ')}${value.length > 3 ? '...' : ''}]`;
       }
       if (typeof value === 'object' && value !== null && 'keys' in value) {
         if (type === 'array') {
           return `[${value.keys.slice(0, 3).join(', ')}${value.keys.length > 3 ? '...' : ''}]`;
         } else {
           return `{${value.keys.slice(0, 3).join(', ')}${value.keys.length > 3 ? '...' : ''}}`;
         }
       }
       return String(value);
     };
    
    return (
      <div className={`${level > 0 ? styles.nestedTable : styles.jsonTable} ${level > 0 ? styles.nestedTableIndented : ''}`}>
        <div className={level > 0 ? styles.nestedTableBody : styles.jsonTableBody}>
          {data.keys.map((key, index) => {
            const typeClass = data.types[index] ? `jsonValue${data.types[index].charAt(0).toUpperCase() + data.types[index].slice(1)}` : '';
            const typeClassName = styles[typeClass] || '';
            const rowPath = `${parentPath}.${key}`;
            const isCollapsed = collapsedRows.has(rowPath);
            const shouldShowCollapse = isLongContent(data.values[index], data.types[index]);
            
            return (
              <div 
                key={index} 
                className={`${level > 0 ? styles.nestedTableRow : styles.jsonTableRow} ${isCollapsed ? styles.collapsedRow : styles.notCollapsedRow}`}
              >
                <div className={level > 0 ? styles.nestedTableKey : styles.jsonTableKey}>
                  <span className={styles.jsonKey}>{key}</span>
                  {shouldShowCollapse && (
                    <button 
                      className={styles.collapseButton}
                      onClick={() => toggleCollapse(rowPath)}
                      title={isCollapsed ? 'Expand' : 'Collapse'}
                    >
                      {isCollapsed ? '▶' : '▼'}
                    </button>
                  )}
                </div>
                <div className={`${level > 0 ? styles.nestedTableValue : styles.jsonTableValue} ${typeClassName}`}>
                  {data.isNested[index] ? (
                    <div>
                      {shouldShowCollapse && isCollapsed ? (
                        <span className={styles.jsonValuePreview}>
                          {getPreview(data.values[index], data.types[index])}
                        </span>
                      ) : (
                        data.values[index].isArray ? (
                          <div className={data.keys[index] === '' ? styles.arrayItemsFullWidth : styles.arrayItems}>
                            {isCollapsed ? (
                              <div className={styles.arrayPreview}>
                                {data.values[index].items.slice(0, 10).map((item: any) => String(item)).join(', ')}               
                                {data.values[index].length > 10 && `, ... (${data.values[index].length} items)`}
                              </div>
                            ) : (
                              <>
                                 {data.values[index].items.map((item: any, itemIndex: number) => (
                                   <div key={itemIndex} className={styles.arrayItem}>
                                     <span className={`${styles.arrayValue} ${typeof item === 'number' ? styles.jsonValueNumber : typeof item === 'string' ? styles.jsonValueString : styles.jsonValue}`}>
                                       {String(item)}
                                     </span>
                                   </div>
                                 ))}
                              </>
                            )}
                          </div>
                        ) : (
                          typeof data.values[index] === 'object' && data.values[index] !== null && 'keys' in data.values[index] ? 
                            renderTable(data.values[index], level + 1, rowPath) : 
                            <span className={styles.jsonValue}>Error: Invalid nested data</span>
                        )
                      )}
                    </div>
                  ) : (
                    <div className={styles.valueContainer}>
                      {shouldShowCollapse && isCollapsed ? (
                        <span className={styles.jsonValuePreview}>
                          {getPreview(data.values[index], data.types[index])}
                        </span>
                      ) : (
                        <span 
                          className={`${styles.jsonValue} ${
                            data.types[index] === 'number' ? styles.jsonValueNumber : 
                            data.types[index] === 'boolean' ? styles.jsonValueBoolean : 
                            data.types[index] === 'string' ? styles.jsonValueString : ''
                          }`}
                        >
                          {String(data.values[index])}
                        </span>
                      )}
                    </div>
                  )}
                </div>
              </div>
            );
          })}
        </div>
      </div>
    );
  };

  try {
    const parsedJson = JSON.parse(previewContent);
    
    let preprocessedData;
    if (Array.isArray(parsedJson)) {
      preprocessedData = preprocessJson(parsedJson, 'root');
    } else if (typeof parsedJson === 'object' && parsedJson !== null) {
      if (parsedJson.result && typeof parsedJson.result === 'string') {
        try {
          const parsedResult = JSON.parse(parsedJson.result);
          parsedJson.result = parsedResult;
        } catch (e) {
          // If parsing fails, keep as string - it will be handled by the string processing logic
        }
      }
      
      const entries = Object.entries(parsedJson);
      
      preprocessedData = {
        keys: entries.map(([key]) => key),
        values: entries.map(([key, value]) => {
          if (typeof value === 'object' && value !== null) {
            const processed = preprocessJson(value, '');
            return processed;
          } else if (typeof value === 'string') {
            try {
              const parsedString = JSON.parse(value);
              if (typeof parsedString === 'object' && parsedString !== null) {
                return preprocessJson(parsedString, '');
              } else {
                let processedValue = value.replace(/\\n/g, ' ').replace(/\n/g, ' ');
                const numValue = parseFloat(value);
                if (!isNaN(numValue) && (key.toLowerCase().includes('timestamp') || key.toLowerCase().includes('time'))) {
                  processedValue = formatTimestamp(value);
                }
                return String(processedValue);
              }
            } catch (e) {
              let processedValue = value.replace(/\\n/g, ' ').replace(/\n/g, ' ');
              const numValue = parseFloat(value);
              if (!isNaN(numValue) && (key.toLowerCase().includes('timestamp') || key.toLowerCase().includes('time'))) {
                processedValue = formatTimestamp(value);
              }
              return String(processedValue);
            }
          } else {
            let processedValue = value;
            
             if (typeof value === 'number' && (key.toLowerCase().includes('timestamp') || key.toLowerCase().includes('time'))) {
               processedValue = formatTimestamp(value);
               return String(processedValue);
             }
             
             return processedValue;
          }
        }),
        types: entries.map(([, value]) => {
          if (typeof value === 'object' && value !== null) {
            return Array.isArray(value) ? 'array' : 'object';
          } else if (typeof value === 'string') {
            try {
              const parsedString = JSON.parse(value);
              if (typeof parsedString === 'object' && parsedString !== null) {
                return Array.isArray(parsedString) ? 'array' : 'object';
              }
            } catch (e) {
              // Ignore parsing errors
            }
            return 'string';
          }
          return typeof value;
        }),
        isNested: entries.map(([, value]) => {
          if (typeof value === 'object' && value !== null) {
            return true;
          } else if (typeof value === 'string') {
            try {
              const parsedString = JSON.parse(value);
              return typeof parsedString === 'object' && parsedString !== null;
            } catch (e) {
              return false;
            }
          }
          return false;
        })
      };
      console.log(preprocessedData);
    } else {
      preprocessedData = {
        keys: ['value'],
        values: [String(parsedJson)],
        types: [typeof parsedJson],
        isNested: [false]
      };
    }
    
    return (
      <div className={styles.jsonContainer}>
        <div className={styles.jsonHeader}>
          <div className={styles.jsonHeaderRight}>
            <span className={styles.jsonSize}>{preprocessedData.keys.length} {t('files.preview.json.properties', 'properties')}</span>
          </div>
        </div>
        {renderTable(preprocessedData, 0, 'root')}
      </div>
    );
  } catch (parseError) {
    const rawData = {
      keys: ['Raw Content'],
      values: [previewContent],
      types: ['string'],
      isNested: [false]
    };
    
    return (
      <div className={styles.jsonContainer}>
        <div className={styles.jsonHeader}>
          <span className={styles.jsonTitle}>{t('files.preview.json.invalid', 'Raw Content (Invalid JSON)')}: {fileName}</span>
          <div className={styles.jsonHeaderRight}>
            <button 
              className={styles.copyButton}
              onClick={handleCopyJson}
              title={t('files.preview.json.copyRaw', 'Copy content to clipboard')}
            >
              📋 {t('common.copy', 'Copy')}
            </button>
          </div>
        </div>
        {renderTable(rawData)}
      </div>
    );
  }
}

