import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';

import '../data/variety_repository.dart';
import '../db/enums.dart';
import '../di/injector.dart';
import '../domain/seed_viability.dart';
import '../i18n/strings.g.dart';
import '../services/share_catalog_service.dart';
import '../state/inventory_cubit.dart';
import 'app_drawer.dart';
import 'draft_triage.dart';
import 'quantity_kind_l10n.dart';
import 'quantity_picker.dart';
import 'quick_add_sheet.dart';
import 'seed_glyph.dart';
import 'theme.dart';
import 'variety_detail_screen.dart' show shareStatusLabel;

/// The inventory home: a searchable list of seeds grouped by category, with a
/// quick-add FAB. Driven by [InventoryCubit] over the encrypted DB stream.
class InventoryListScreen extends StatelessWidget {
  const InventoryListScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final t = context.t;
    return Scaffold(
      appBar: AppBar(
        title: Text(t.inventory.title),
        actions: [
          // The paper bridge: only offered once something is marked to share.
          BlocSelector<InventoryCubit, InventoryState, bool>(
            selector: (state) => state.hasShared,
            builder: (context, hasShared) => hasShared
                ? IconButton(
                    key: const Key('inventory.printCatalog'),
                    icon: const Icon(Icons.print_outlined),
                    tooltip: t.share.printCatalog,
                    onPressed: () => _printCatalog(context),
                  )
                : const SizedBox.shrink(),
          ),
          IconButton(
            key: const Key('inventory.captureBurst'),
            icon: const Icon(Icons.add_a_photo_outlined),
            tooltip: t.draft.capture,
            onPressed: () => _captureBurst(context),
          ),
        ],
      ),
      drawer: const AppDrawer(),
      floatingActionButton: FloatingActionButton(
        key: const Key('inventory.addFab'),
        tooltip: t.quickAdd.title,
        onPressed: () => showQuickAddSheet(
          context,
          repository: context.read<VarietyRepository>(),
        ),
        child: const Icon(Icons.add),
      ),
      body: BlocBuilder<InventoryCubit, InventoryState>(
        builder: (context, state) {
          if (state.loading) {
            return const Center(child: CircularProgressIndicator());
          }
          return Column(
            children: [
              if (state.drafts.isNotEmpty)
                _TriageBanner(count: state.drafts.length),
              Padding(
                padding: const EdgeInsets.fromLTRB(12, 12, 12, 4),
                child: TextField(
                  key: const Key('inventory.search'),
                  decoration: InputDecoration(
                    hintText: t.inventory.searchHint,
                    prefixIcon: const Icon(Icons.search, color: seedMuted),
                    hintStyle: const TextStyle(color: seedMuted),
                    filled: true,
                    fillColor: Colors.white,
                    isDense: true,
                    contentPadding: const EdgeInsets.symmetric(vertical: 14),
                    border: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(28),
                      borderSide: BorderSide.none,
                    ),
                  ),
                  onChanged: context.read<InventoryCubit>().search,
                ),
              ),
              _FilterBar(state: state),
              Expanded(
                child: _InventoryBody(
                  items: state.visibleItems,
                  // Distinguish "no seeds at all" from "filters hid them all".
                  filtered:
                      state.categoryFilter.isNotEmpty ||
                      state.typeFilter.isNotEmpty ||
                      state.organicOnly ||
                      state.needsReproductionOnly ||
                      state.sharingOnly,
                ),
              ),
            ],
          );
        },
      ),
    );
  }

  /// Assembles the localized rows of the "what I share" catalog and saves it
  /// as a PDF wherever the user chooses.
  Future<void> _printCatalog(BuildContext context) async {
    final t = context.t;
    final repository = context.read<VarietyRepository>();
    final messenger = ScaffoldMessenger.of(context);
    final date = DateTime.now();
    final dateLabel = MaterialLocalizations.of(context).formatFullDate(date);
    final entries = await repository.sharedCatalog();
    final rows = [
      for (final e in entries)
        ShareCatalogRow(
          name: e.varietyLabel,
          scientificName: e.scientificName,
          mode: shareStatusLabel(t, e.offerStatus),
          details: _catalogDetails(t, e),
        ),
    ];
    final saved = await getIt<ShareCatalogService>().saveCatalog(
      title: t.share.catalogTitle,
      date: dateLabel,
      suggestedName:
          'tanemaki-catalog-${date.toIso8601String().substring(0, 10)}.pdf',
      rows: rows,
    );
    messenger.showSnackBar(
      SnackBar(content: Text(saved ? t.share.catalogSaved : t.share.cancelled)),
    );
  }

  /// The batch facts line of one catalog entry ("Seeds · Year 2024 · 2 cobs").
  String? _catalogDetails(Translations t, SharedCatalogEntry e) {
    final parts = <String>[
      lotTypeLabel(t, e.type),
      if (e.harvestYear != null) t.detail.year(year: e.harvestYear!),
      if (e.quantity != null) quantityDisplay(t, e.quantity!),
    ];
    return parts.isEmpty ? null : parts.join(' · ');
  }

  Future<void> _captureBurst(BuildContext context) async {
    final t = context.t;
    final repository = context.read<VarietyRepository>();
    final messenger = ScaffoldMessenger.of(context);
    final count = await captureDraftBurst(context, repository);
    if (count > 0) {
      messenger.showSnackBar(
        SnackBar(content: Text(t.draft.captured(n: count))),
      );
    }
  }
}

/// A tappable banner announcing how many photo-first captures are waiting to be
/// named. Opens the "to catalogue" tray.
class _TriageBanner extends StatelessWidget {
  const _TriageBanner({required this.count});

  final int count;

  @override
  Widget build(BuildContext context) {
    final t = context.t;
    return Material(
      color: seedAvatar,
      child: ListTile(
        key: const Key('inventory.triageBanner'),
        leading: const Icon(Icons.inventory_2_outlined, color: seedGreen),
        title: Text(
          t.draft.triageCount(n: count),
          style: const TextStyle(fontWeight: FontWeight.w500),
        ),
        trailing: const Icon(Icons.chevron_right),
        onTap: () =>
            showTriageSheet(context, context.read<VarietyRepository>()),
      ),
    );
  }
}

/// A horizontally scrolling row of filter chips: one per category in use plus
/// one per lot form actually held. Only shown once there is something to filter.
class _FilterBar extends StatelessWidget {
  const _FilterBar({required this.state});

  final InventoryState state;

  @override
  Widget build(BuildContext context) {
    final t = context.t;
    final cubit = context.read<InventoryCubit>();
    final categories = state.categories;
    // Only offer form chips for forms that some variety actually holds.
    final forms = <LotType>[
      for (final type in LotType.values)
        if (state.items.any((i) => i.lotTypes.contains(type))) type,
    ];
    // Only offer the eco chip when some variety is flagged organic.
    final hasOrganic = state.hasOrganic;
    // Only offer the "to regrow" chip when something is flagged for it.
    final hasNeedsReproduction = state.hasNeedsReproduction;
    // Only offer the "I share" chip when some lot is marked to share.
    final hasShared = state.hasShared;
    if (categories.isEmpty &&
        forms.isEmpty &&
        !hasOrganic &&
        !hasNeedsReproduction &&
        !hasShared) {
      return const SizedBox.shrink();
    }

    final chips = <Widget>[
      if (hasShared)
        FilterChip(
          key: const Key('inventory.filter.sharing'),
          avatar: Icon(
            Icons.volunteer_activism_outlined,
            size: 18,
            color: state.sharingOnly ? null : seedGreen,
          ),
          label: Text(t.share.filterChip),
          selected: state.sharingOnly,
          onSelected: (_) => cubit.toggleSharingOnly(),
        ),
      if (hasOrganic)
        FilterChip(
          key: const Key('inventory.filter.organic'),
          avatar: Icon(
            Icons.eco,
            size: 18,
            color: state.organicOnly ? null : seedGreen,
          ),
          label: Text(t.editVariety.organic),
          selected: state.organicOnly,
          onSelected: (_) => cubit.toggleOrganicOnly(),
        ),
      if (hasNeedsReproduction)
        FilterChip(
          key: const Key('inventory.filter.needsReproduction'),
          avatar: Icon(
            Icons.autorenew,
            size: 18,
            color: state.needsReproductionOnly ? null : seedGreen,
          ),
          label: Text(t.inventory.needsReproductionFilter),
          selected: state.needsReproductionOnly,
          onSelected: (_) => cubit.toggleNeedsReproductionOnly(),
        ),
      for (final category in categories)
        FilterChip(
          key: Key('inventory.filter.category.$category'),
          label: Text(category),
          selected: state.categoryFilter.contains(category),
          onSelected: (_) => cubit.toggleCategory(category),
        ),
      for (final form in forms)
        FilterChip(
          key: Key('inventory.filter.type.${form.name}'),
          label: Text(lotTypeLabel(t, form)),
          selected: state.typeFilter.contains(form),
          onSelected: (_) => cubit.toggleType(form),
        ),
    ];
    final hasActiveFilter =
        state.categoryFilter.isNotEmpty ||
        state.typeFilter.isNotEmpty ||
        state.organicOnly ||
        state.needsReproductionOnly ||
        state.sharingOnly;

    return SingleChildScrollView(
      scrollDirection: Axis.horizontal,
      padding: const EdgeInsets.symmetric(horizontal: 12),
      child: Row(
        children: [
          for (final chip in chips)
            Padding(
              padding: const EdgeInsetsDirectional.only(end: 8),
              child: chip,
            ),
          if (hasActiveFilter)
            TextButton.icon(
              key: const Key('inventory.filter.clear'),
              onPressed: cubit.clearFilters,
              icon: const Icon(Icons.clear, size: 18),
              label: Text(t.inventory.clearFilters),
            ),
        ],
      ),
    );
  }
}

class _InventoryBody extends StatelessWidget {
  const _InventoryBody({required this.items, this.filtered = false});

  final List<VarietyListItem> items;

  /// Whether a filter is active, so an empty list reads "no matches" rather
  /// than "no seeds yet".
  final bool filtered;

  @override
  Widget build(BuildContext context) {
    final t = context.t;
    if (items.isEmpty) {
      return Center(
        child: Padding(
          padding: const EdgeInsets.all(24),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              SeedGlyph(
                SeedGlyphs.jars,
                size: 72,
                color: seedGreen.withValues(alpha: 0.5),
              ),
              const SizedBox(height: 16),
              Text(
                filtered ? t.inventory.noMatches : t.inventory.empty,
                textAlign: TextAlign.center,
                style: Theme.of(context).textTheme.bodyLarge,
              ),
            ],
          ),
        ),
      );
    }

    // Items arrive ordered by category then label; insert a header whenever the
    // category changes.
    final rows = <Widget>[];
    String? currentCategory;
    for (final item in items) {
      final category = item.category ?? t.inventory.uncategorized;
      if (category != currentCategory) {
        currentCategory = category;
        rows.add(_CategoryHeader(title: category));
      }
      rows.add(_VarietyTile(item: item));
    }
    return ListView(children: rows);
  }
}

class _CategoryHeader extends StatelessWidget {
  const _CategoryHeader({required this.title});

  final String title;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.fromLTRB(16, 18, 16, 6),
      // Base on the text theme so it honours the system font-scale factor.
      child: Text(
        title,
        style: Theme.of(context).textTheme.titleMedium?.copyWith(
          fontWeight: FontWeight.w500,
          color: seedGreen,
        ),
      ),
    );
  }
}

class _VarietyTile extends StatelessWidget {
  const _VarietyTile({required this.item});

  final VarietyListItem item;

  @override
  Widget build(BuildContext context) {
    void open() => context.push('/variety/${item.id}');
    return ListTile(
      leading: _Avatar(item: item),
      title: Text(
        item.label,
        style: const TextStyle(fontWeight: FontWeight.bold),
      ),
      subtitle: item.scientificName == null
          ? null
          : Text(
              item.scientificName!,
              style: const TextStyle(fontStyle: FontStyle.italic),
            ),
      trailing: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          if (item.isShared)
            Padding(
              padding: const EdgeInsetsDirectional.only(end: 4),
              child: Tooltip(
                key: Key('inventory.shared.${item.id}'),
                message: context.t.share.filterChip,
                child: const Icon(
                  Icons.volunteer_activism_outlined,
                  size: 20,
                  color: seedGreen,
                ),
              ),
            ),
          if (item.isOrganic)
            Padding(
              padding: const EdgeInsetsDirectional.only(end: 4),
              child: Tooltip(
                key: Key('inventory.organic.${item.id}'),
                message: context.t.editVariety.organic,
                child: const Icon(Icons.eco, size: 20, color: seedGreen),
              ),
            ),
          _ViabilityDot(item.viability),
          IconButton(
            icon: const Icon(Icons.edit_outlined),
            // Action colour: this is a tap target, not secondary text.
            color: seedGreen,
            tooltip: context.t.common.edit,
            onPressed: open,
          ),
        ],
      ),
      onTap: open,
    );
  }
}

/// A small aging indicator on a list tile: an amber clock when some seed lot is
/// in its last viable year, a red alert when one is past typical viability.
/// Renders nothing for fresh or unknown lots.
class _ViabilityDot extends StatelessWidget {
  const _ViabilityDot(this.status);

  final SeedViability status;

  @override
  Widget build(BuildContext context) {
    final t = context.t;
    final expired = status == SeedViability.expired;
    if (status != SeedViability.expiringSoon && !expired) {
      return const SizedBox.shrink();
    }
    final scheme = Theme.of(context).colorScheme;
    return Tooltip(
      key: Key('inventory.viability.${expired ? 'expired' : 'soon'}'),
      message: expired ? t.viability.expired : t.viability.expiringSoon,
      child: Icon(
        expired ? Icons.error_outline : Icons.schedule,
        size: 20,
        color: expired ? scheme.error : const Color(0xFFB26A00),
      ),
    );
  }
}

/// Rounded-square photo thumbnail, or a green initial circle when there is none.
class _Avatar extends StatelessWidget {
  const _Avatar({required this.item});

  final VarietyListItem item;

  @override
  Widget build(BuildContext context) {
    final photo = item.photo;
    // Decorative: the tile title already announces the variety name, so keep
    // the thumbnail / initial out of the semantics tree.
    if (photo != null) {
      return ExcludeSemantics(
        child: ClipRRect(
          borderRadius: BorderRadius.circular(8),
          child: Image.memory(photo, width: 48, height: 48, fit: BoxFit.cover),
        ),
      );
    }
    final trimmed = item.label.trim();
    final initial = trimmed.isEmpty
        ? '?'
        : trimmed.substring(0, 1).toUpperCase();
    return ExcludeSemantics(
      child: CircleAvatar(
        backgroundColor: seedAvatar,
        foregroundColor: seedOnAvatar,
        child: Text(initial),
      ),
    );
  }
}
