import 'dart:io';
import 'dart:typed_data';
import 'dart:math';

/// Generates a simple tree icon PNG
void main() async {
  const size = 1024;
  final pixels = Uint8List(size * size * 4);

  // Fill with white background
  for (var i = 0; i < pixels.length; i += 4) {
    pixels[i] = 255;     // R
    pixels[i + 1] = 255; // G
    pixels[i + 2] = 255; // B
    pixels[i + 3] = 255; // A
  }

  // Tree colors (muted teal from our theme)
  const treeR = 74;  // 0x4A
  const treeG = 144; // 0x90
  const treeB = 164; // 0xA4

  // Trunk color (darker)
  const trunkR = 90;
  const trunkG = 70;
  const trunkB = 55;

  // Draw tree trunk (rectangle)
  final trunkLeft = (size * 0.44).round();
  final trunkRight = (size * 0.56).round();
  final trunkTop = (size * 0.65).round();
  final trunkBottom = (size * 0.85).round();

  for (var y = trunkTop; y < trunkBottom; y++) {
    for (var x = trunkLeft; x < trunkRight; x++) {
      final i = (y * size + x) * 4;
      pixels[i] = trunkR;
      pixels[i + 1] = trunkG;
      pixels[i + 2] = trunkB;
      pixels[i + 3] = 255;
    }
  }

  // Draw tree canopy (three triangles stacked)
  void drawTriangle(int centerX, int topY, int height, int baseWidth) {
    for (var y = topY; y < topY + height; y++) {
      final progress = (y - topY) / height;
      final halfWidth = (baseWidth * progress / 2).round();
      for (var x = centerX - halfWidth; x <= centerX + halfWidth; x++) {
        if (x >= 0 && x < size && y >= 0 && y < size) {
          final i = (y * size + x) * 4;
          pixels[i] = treeR;
          pixels[i + 1] = treeG;
          pixels[i + 2] = treeB;
          pixels[i + 3] = 255;
        }
      }
    }
  }

  final centerX = size ~/ 2;

  // Top triangle (smallest)
  drawTriangle(centerX, (size * 0.15).round(), (size * 0.20).round(), (size * 0.35).round());

  // Middle triangle
  drawTriangle(centerX, (size * 0.28).round(), (size * 0.22).round(), (size * 0.48).round());

  // Bottom triangle (largest)
  drawTriangle(centerX, (size * 0.42).round(), (size * 0.26).round(), (size * 0.58).round());

  // Encode as PNG
  final png = encodePng(size, size, pixels);

  // Write to file
  final file = File('assets/icon/app_icon.png');
  await file.writeAsBytes(png);
  print('Generated app_icon.png');

  // Also create foreground version (same but smaller for adaptive icons)
  final foregroundFile = File('assets/icon/app_icon_foreground.png');
  await foregroundFile.writeAsBytes(png);
  print('Generated app_icon_foreground.png');
}

/// Simple PNG encoder (no compression for simplicity)
Uint8List encodePng(int width, int height, Uint8List rgba) {
  final output = BytesBuilder();

  // PNG signature
  output.add([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]);

  // IHDR chunk
  final ihdr = BytesBuilder();
  ihdr.add(_int32be(width));
  ihdr.add(_int32be(height));
  ihdr.addByte(8);  // bit depth
  ihdr.addByte(6);  // color type (RGBA)
  ihdr.addByte(0);  // compression
  ihdr.addByte(0);  // filter
  ihdr.addByte(0);  // interlace
  _writeChunk(output, 'IHDR', ihdr.toBytes());

  // IDAT chunk (image data with zlib compression)
  // For simplicity, we'll use store (no compression)
  final rawData = BytesBuilder();
  for (var y = 0; y < height; y++) {
    rawData.addByte(0); // filter type: None
    for (var x = 0; x < width; x++) {
      final i = (y * width + x) * 4;
      rawData.addByte(rgba[i]);     // R
      rawData.addByte(rgba[i + 1]); // G
      rawData.addByte(rgba[i + 2]); // B
      rawData.addByte(rgba[i + 3]); // A
    }
  }

  final compressed = _deflateStore(rawData.toBytes());
  _writeChunk(output, 'IDAT', compressed);

  // IEND chunk
  _writeChunk(output, 'IEND', Uint8List(0));

  return output.toBytes();
}

Uint8List _int32be(int value) {
  return Uint8List.fromList([
    (value >> 24) & 0xFF,
    (value >> 16) & 0xFF,
    (value >> 8) & 0xFF,
    value & 0xFF,
  ]);
}

void _writeChunk(BytesBuilder output, String type, Uint8List data) {
  output.add(_int32be(data.length));
  final typeBytes = type.codeUnits;
  output.add(typeBytes);
  output.add(data);

  // CRC32 of type + data
  final crcData = Uint8List(typeBytes.length + data.length);
  crcData.setAll(0, typeBytes);
  crcData.setAll(typeBytes.length, data);
  output.add(_int32be(_crc32(crcData)));
}

/// Simple deflate with store (no compression)
Uint8List _deflateStore(Uint8List data) {
  final output = BytesBuilder();

  // zlib header
  output.addByte(0x78); // CMF
  output.addByte(0x01); // FLG (no dict, fastest)

  // Split into blocks of max 65535 bytes
  const maxBlock = 65535;
  var offset = 0;

  while (offset < data.length) {
    final remaining = data.length - offset;
    final blockSize = remaining > maxBlock ? maxBlock : remaining;
    final isLast = offset + blockSize >= data.length;

    output.addByte(isLast ? 0x01 : 0x00); // BFINAL + BTYPE (store)
    output.addByte(blockSize & 0xFF);
    output.addByte((blockSize >> 8) & 0xFF);
    output.addByte((~blockSize) & 0xFF);
    output.addByte(((~blockSize) >> 8) & 0xFF);

    output.add(data.sublist(offset, offset + blockSize));
    offset += blockSize;
  }

  // Adler-32 checksum
  var s1 = 1;
  var s2 = 0;
  for (var i = 0; i < data.length; i++) {
    s1 = (s1 + data[i]) % 65521;
    s2 = (s2 + s1) % 65521;
  }
  final adler = (s2 << 16) | s1;
  output.add(_int32be(adler));

  return output.toBytes();
}

int _crc32(Uint8List data) {
  var crc = 0xFFFFFFFF;
  for (var byte in data) {
    crc ^= byte;
    for (var i = 0; i < 8; i++) {
      crc = (crc & 1) != 0 ? (crc >> 1) ^ 0xEDB88320 : crc >> 1;
    }
  }
  return crc ^ 0xFFFFFFFF;
}
