import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../models/office.dart';
import '../../models/profile.dart';
import '../../models/team.dart';
import '../../providers/teams_provider.dart';
import '../../providers/profile_provider.dart';
import '../../providers/tickets_provider.dart';
import '../../providers/supabase_provider.dart';
import '../../utils/supabase_response.dart';
import 'package:tasq/widgets/multi_select_picker.dart';
import '../../theme/app_surfaces.dart';
import '../../widgets/tasq_adaptive_list.dart';

// Note: `officesProvider` is provided globally in `tickets_provider.dart` so
// we reuse that StreamProvider here (avoids duplicate queries).

class TeamsScreen extends ConsumerStatefulWidget {
  const TeamsScreen({super.key});

  @override
  ConsumerState<TeamsScreen> createState() => _TeamsScreenState();
}

class _TeamsScreenState extends ConsumerState<TeamsScreen> {
  final TextEditingController _searchController = TextEditingController();
  String? _selectedOfficeId;
  String? _selectedLeaderId;

  @override
  void dispose() {
    _searchController.dispose();
    super.dispose();
  }

  bool get _hasFilters {
    return _searchController.text.trim().isNotEmpty ||
        _selectedOfficeId != null ||
        _selectedLeaderId != null;
  }

  @override
  Widget build(BuildContext context) {
    final teamsAsync = ref.watch(teamsProvider);
    final profilesAsync = ref.watch(profilesProvider);
    final officesAsync = ref.watch(officesProvider);
    final teamMembersAsync = ref.watch(teamMembersProvider);

    return Scaffold(
      body: teamsAsync.when(
        data: (teams) {
          final profiles = profilesAsync.valueOrNull ?? [];
          final offices = officesAsync.valueOrNull ?? [];
          final teamMembers = teamMembersAsync.valueOrNull ?? [];
          final profileById = {for (var p in profiles) p.id: p};
          final officeById = {for (var o in offices) o.id: o};

          // filters
          final itStaff = profiles.where((p) => p.role == 'it_staff').toList();
          final officeOptions = <DropdownMenuItem<String?>>[
            const DropdownMenuItem<String?>(
              value: null,
              child: Text('All offices'),
            ),
            ...offices.map(
              (o) => DropdownMenuItem(value: o.id, child: Text(o.name)),
            ),
          ];
          final leaderOptions = <DropdownMenuItem<String?>>[
            const DropdownMenuItem<String?>(
              value: null,
              child: Text('All leaders'),
            ),
            ...itStaff.map(
              (p) => DropdownMenuItem(
                value: p.id,
                child: Text(p.fullName.isNotEmpty ? p.fullName : p.id),
              ),
            ),
          ];

          final filteredTeams = teams.where((t) {
            final matchesName =
                _searchController.text.trim().isEmpty ||
                t.name.toLowerCase().contains(
                  _searchController.text.trim().toLowerCase(),
                );
            final matchesOffice =
                _selectedOfficeId == null ||
                t.officeIds.contains(_selectedOfficeId);
            final matchesLeader =
                _selectedLeaderId == null || t.leaderId == _selectedLeaderId;
            return matchesName && matchesOffice && matchesLeader;
          }).toList();

          final filterHeader = Wrap(
            spacing: 12,
            runSpacing: 12,
            crossAxisAlignment: WrapCrossAlignment.center,
            children: [
              SizedBox(
                width: 280,
                child: TextField(
                  controller: _searchController,
                  onChanged: (_) => setState(() {}),
                  decoration: const InputDecoration(
                    labelText: 'Search team name',
                    prefixIcon: Icon(Icons.search),
                  ),
                ),
              ),
              SizedBox(
                width: 200,
                child: DropdownButtonFormField<String?>(
                  isExpanded: true,
                  key: ValueKey(_selectedOfficeId),
                  initialValue: _selectedOfficeId,
                  items: officeOptions,
                  onChanged: (v) => setState(() => _selectedOfficeId = v),
                  decoration: const InputDecoration(labelText: 'Office'),
                ),
              ),
              SizedBox(
                width: 220,
                child: DropdownButtonFormField<String?>(
                  isExpanded: true,
                  key: ValueKey(_selectedLeaderId),
                  initialValue: _selectedLeaderId,
                  items: leaderOptions,
                  onChanged: (v) => setState(() => _selectedLeaderId = v),
                  decoration: const InputDecoration(labelText: 'Team leader'),
                ),
              ),
              if (_hasFilters)
                TextButton.icon(
                  onPressed: () => setState(() {
                    _searchController.clear();
                    _selectedOfficeId = null;
                    _selectedLeaderId = null;
                  }),
                  icon: const Icon(Icons.close),
                  label: const Text('Clear'),
                ),
            ],
          );

          final listBody = TasQAdaptiveList<Team>(
            items: filteredTeams,
            filterHeader: filterHeader,
            columns: [
              TasQColumn<Team>(
                header: 'Name',
                cellBuilder: (context, team) => Text(team.name),
              ),
              TasQColumn<Team>(
                header: 'Leader',
                cellBuilder: (context, team) {
                  final leader = profileById[team.leaderId];
                  return Text(leader?.fullName ?? team.leaderId);
                },
              ),
              TasQColumn<Team>(
                header: 'Offices',
                cellBuilder: (context, team) {
                  final officeNames = team.officeIds
                      .map((id) => officeById[id]?.name ?? id)
                      .join(', ');
                  return Text(officeNames);
                },
              ),
              TasQColumn<Team>(
                header: 'Members',
                cellBuilder: (context, team) {
                  final members = team.members(teamMembers);
                  final memberNames = members
                      .map((id) => profileById[id]?.fullName ?? id)
                      .join(', ');
                  return Text(memberNames);
                },
              ),
            ],
            mobileTileBuilder: (context, team, actions) {
              final leader = profileById[team.leaderId];
              final officeNames = team.officeIds
                  .map((id) => officeById[id]?.name ?? id)
                  .join(', ');
              final members = team.members(teamMembers);
              final memberNames = members
                  .map((id) => profileById[id]?.fullName ?? id)
                  .join(', ');
              return ListTile(
                title: Text(team.name),
                subtitle: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text('Leader: ${leader?.fullName ?? team.leaderId}'),
                    Text('Offices: $officeNames'),
                    Text('Members: $memberNames'),
                  ],
                ),
                trailing: Row(
                  mainAxisSize: MainAxisSize.min,
                  children: actions,
                ),
                onTap: () => _showTeamDialog(context, team: team),
              );
            },
            rowActions: (team) => [
              IconButton(
                icon: const Icon(Icons.edit),
                tooltip: 'Edit',
                onPressed: () => _showTeamDialog(context, team: team),
              ),
              IconButton(
                icon: const Icon(Icons.delete),
                tooltip: 'Delete',
                onPressed: () => _deleteTeam(context, team.id),
              ),
            ],
          );

          return Column(
            mainAxisSize: MainAxisSize.max,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              Padding(
                padding: const EdgeInsets.only(top: 16, bottom: 8),
                child: Stack(
                  alignment: Alignment.center,
                  children: [
                    Align(
                      alignment: Alignment.center,
                      child: Text(
                        'Team Management',
                        textAlign: TextAlign.center,
                        style: Theme.of(context).textTheme.titleLarge?.copyWith(
                          fontWeight: FontWeight.w700,
                        ),
                      ),
                    ),
                  ],
                ),
              ),
              Expanded(child: listBody),
            ],
          );
        },
        loading: () => const Center(child: CircularProgressIndicator()),
        error: (err, stack) => Center(child: Text('Error: $err')),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => _showTeamDialog(context),
        tooltip: 'Add Team',
        child: const Icon(Icons.add),
      ),
    );
  }

  void _showTeamDialog(BuildContext context, {Team? team}) async {
    final profiles = ref.read(profilesProvider).valueOrNull ?? [];
    // officesProvider is a StreamProvider (global) — try to read the latest
    // synchronous value first, otherwise await the first stream event.
    final officesSync = ref.read(officesProvider).valueOrNull;
    final List<Office> offices =
        officesSync ?? await ref.read(officesProvider.future);
    if (!context.mounted) return;
    final itStaff = profiles.where((p) => p.role == 'it_staff').toList();
    final nameController = TextEditingController(text: team?.name ?? '');
    String? leaderId = team?.leaderId;
    List<String> selectedOffices = List<String>.from(team?.officeIds ?? []);
    List<String> selectedMembers = [];
    final isEdit = team != null;

    // If editing, fetch current members
    if (isEdit) {
      final members = ref.read(teamMembersProvider).valueOrNull ?? [];
      selectedMembers = members
          .where((m) => m.teamId == team.id)
          .map((m) => m.userId)
          .toList();
    }

    final bool isMobileDialog = MediaQuery.of(context).size.width <= 600;
    const double kDialogMaxWidth = 720;

    // Dialog content builder (captures outer local vars like leaderId,
    // selectedOffices, selectedMembers, nameController).
    Widget buildFormContent(StateSetter setState) {
      return SingleChildScrollView(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            TextField(
              controller: nameController,
              decoration: const InputDecoration(labelText: 'Team Name'),
            ),
            const SizedBox(height: 12),
            DropdownButtonFormField<String>(
              initialValue: leaderId,
              items: [
                for (final p in itStaff)
                  DropdownMenuItem(
                    value: p.id,
                    child: Text(p.fullName.isNotEmpty ? p.fullName : p.id),
                  ),
              ],
              onChanged: (v) => setState(() => leaderId = v),
              decoration: const InputDecoration(labelText: 'Team Leader'),
            ),
            const SizedBox(height: 12),
            // Available offices: exclude offices already assigned to other teams
            Builder(
              builder: (context) {
                final allTeams =
                    ref.read(teamsProvider).valueOrNull ?? <Team>[];
                final assignedOfficeIds = allTeams
                    .where((t) => t.id != team?.id)
                    .expand((t) => t.officeIds)
                    .toSet();
                final availableOffices = offices
                    .where(
                      (o) =>
                          !assignedOfficeIds.contains(o.id) ||
                          selectedOffices.contains(o.id),
                    )
                    .toList();

                return MultiSelectPicker<Office>(
                  label: 'Offices',
                  items: availableOffices,
                  selectedIds: selectedOffices,
                  getId: (o) => o.id,
                  getLabel: (o) => o.name,
                  onChanged: (ids) => setState(() => selectedOffices = ids),
                );
              },
            ),
            const SizedBox(height: 12),
            Builder(
              builder: (context) {
                final members =
                    ref.read(teamMembersProvider).valueOrNull ?? <dynamic>[];
                final assignedUserIds = members
                    .where((m) => m.teamId != team?.id)
                    .map((m) => m.userId)
                    .toSet();
                final availableItStaff = itStaff
                    .where(
                      (p) =>
                          !assignedUserIds.contains(p.id) ||
                          selectedMembers.contains(p.id),
                    )
                    .toList();

                return MultiSelectPicker<Profile>(
                  label: 'Team Members',
                  items: availableItStaff,
                  selectedIds: selectedMembers,
                  getId: (p) => p.id,
                  getLabel: (p) => p.fullName.isNotEmpty ? p.fullName : p.id,
                  onChanged: (ids) => setState(() => selectedMembers = ids),
                );
              },
            ),
          ],
        ),
      );
    }

    Future<void> onSave(StateSetter setState, NavigatorState navigator) async {
      final messenger = ScaffoldMessenger.of(navigator.context);
      final name = nameController.text.trim();
      if (name.isEmpty) {
        ScaffoldMessenger.of(
          context,
        ).showSnackBar(const SnackBar(content: Text('Team name is required')));
        return;
      }
      if (leaderId == null) {
        messenger.showSnackBar(
          const SnackBar(content: Text('Please select a team leader')),
        );
        return;
      }
      if (selectedOffices.isEmpty) {
        messenger.showSnackBar(
          const SnackBar(
            content: Text('Assign at least one office to the team'),
          ),
        );
        return;
      }

      // ensure leader included
      if (leaderId != null && !selectedMembers.contains(leaderId)) {
        selectedMembers = [leaderId!, ...selectedMembers];
      }

      final client = ref.read(supabaseClientProvider);
      try {
        if (isEdit) {
          // update team row
          final upRes = await client
              .from('teams')
              .update({
                'name': name,
                'leader_id': leaderId,
                'office_ids': selectedOffices,
              })
              .eq('id', team.id);
          final upErr = extractSupabaseError(upRes);
          if (upErr != null) throw Exception(upErr);

          // replace members for the team
          final delRes = await client
              .from('team_members')
              .delete()
              .eq('team_id', team.id);
          final delErr = extractSupabaseError(delRes);
          if (delErr != null) throw Exception(delErr);

          if (selectedMembers.isNotEmpty) {
            final rows = selectedMembers
                .map((u) => {'team_id': team.id, 'user_id': u})
                .toList();
            final memRes = await client.from('team_members').insert(rows);
            final memErr = extractSupabaseError(memRes);
            if (memErr != null) throw Exception(memErr);

            // verify members persisted (handle Map or List response)
            final dynamic checkRes = await client
                .from('team_members')
                .select()
                .eq('team_id', team.id);
            if (checkRes is Map && checkRes['error'] != null) {
              throw Exception('Failed to verify team members');
            }
            final List persisted = checkRes is List
                ? List.from(checkRes)
                : (checkRes is Map && checkRes['data'] is List)
                ? List.from(checkRes['data'] as List)
                : <dynamic>[];
            if (persisted.length != selectedMembers.length) {
              throw Exception('Member count mismatch after save');
            }
          }
        } else {
          // create team and insert members
          final insertRes = await client
              .from('teams')
              .insert({
                'name': name,
                'leader_id': leaderId,
                'office_ids': selectedOffices,
              })
              .select()
              .single();

          // normalize inserted row to extract id reliably across client response shapes
          dynamic insertedRow;
          final dynamic insertResValue = insertRes;
          if (insertResValue is List && insertResValue.isNotEmpty) {
            insertedRow = insertResValue.first;
          } else {
            final insertErr = extractSupabaseError(insertResValue);
            if (insertErr != null) throw Exception(insertErr);
            final dataField = insertResValue['data'];
            if (dataField is List && dataField.isNotEmpty) {
              insertedRow = dataField.first;
            } else if (dataField is Map) {
              insertedRow = dataField;
            } else if (insertResValue['id'] != null) {
              insertedRow = insertResValue;
            }
          }

          if (insertedRow == null || insertedRow['id'] == null) {
            throw Exception('Unable to determine created team id');
          }
          final teamId = insertedRow['id'] as String;

          if (selectedMembers.isNotEmpty) {
            final rows = selectedMembers
                .map((u) => {'team_id': teamId, 'user_id': u})
                .toList();
            final memRes = await client.from('team_members').insert(rows);
            final memErr2 = extractSupabaseError(memRes);
            if (memErr2 != null) throw Exception(memErr2);

            // verify members persisted (handle Map or List response)
            final dynamic checkRes = await client
                .from('team_members')
                .select()
                .eq('team_id', teamId);
            if (checkRes is Map && checkRes['error'] != null) {
              throw Exception('Failed to verify team members');
            }
            final List persisted = checkRes is List
                ? List.from(checkRes)
                : (checkRes is Map && checkRes['data'] is List)
                ? List.from(checkRes['data'] as List)
                : <dynamic>[];
            if (persisted.length != selectedMembers.length) {
              throw Exception('Member count mismatch after save');
            }
          }
        }
      } catch (e) {
        messenger.showSnackBar(
          SnackBar(content: Text('Failed to save team: $e')),
        );
        return;
      }

      ref.invalidate(teamsProvider);
      ref.invalidate(teamMembersProvider);
      navigator.pop();
    }

    if (isMobileDialog) {
      // Mobile: bottom sheet presentation
      await showModalBottomSheet<void>(
        context: context,
        isScrollControlled: true,
        shape: AppSurfaces.of(context).dialogShape,
        builder: (sheetContext) {
          return StatefulBuilder(
            builder: (sheetContext, setState) {
              final navigator = Navigator.of(sheetContext);
              return SafeArea(
                child: Padding(
                  padding: EdgeInsets.only(
                    left: 16,
                    right: 16,
                    top: 12,
                    bottom: MediaQuery.of(sheetContext).viewInsets.bottom + 12,
                  ),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        isEdit ? 'Edit Team' : 'Add Team',
                        style: Theme.of(sheetContext).textTheme.titleLarge,
                      ),
                      const SizedBox(height: 8),
                      buildFormContent(setState),
                      const SizedBox(height: 12),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.end,
                        children: [
                          TextButton(
                            onPressed: () => navigator.pop(),
                            child: const Text('Cancel'),
                          ),
                          const SizedBox(width: 8),
                          ElevatedButton(
                            onPressed: () => onSave(setState, navigator),
                            child: Text(isEdit ? 'Save' : 'Add'),
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
              );
            },
          );
        },
      );
    } else {
      // Desktop / Tablet: centered fixed-width AlertDialog
      await showDialog<void>(
        context: context,
        builder: (dialogContext) {
          return Center(
            child: ConstrainedBox(
              constraints: const BoxConstraints(maxWidth: kDialogMaxWidth),
              child: StatefulBuilder(
                builder: (dialogContext, setState) {
                  final navigator = Navigator.of(dialogContext);
                  return AlertDialog(
                    shape: AppSurfaces.of(dialogContext).dialogShape,
                    title: Text(isEdit ? 'Edit Team' : 'Add Team'),
                    content: buildFormContent(setState),
                    actions: [
                      TextButton(
                        onPressed: () => navigator.pop(),
                        child: const Text('Cancel'),
                      ),
                      ElevatedButton(
                        onPressed: () => onSave(setState, navigator),
                        child: Text(isEdit ? 'Save' : 'Add'),
                      ),
                    ],
                  );
                },
              ),
            ),
          );
        },
      );
    }
  }

  void _deleteTeam(BuildContext context, String teamId) async {
    final messenger = ScaffoldMessenger.of(context);

    final confirmed = await showDialog<bool?>(
      context: context,
      builder: (dialogContext) => AlertDialog(
        shape: AppSurfaces.of(dialogContext).dialogShape,
        title: const Text('Delete Team'),
        content: ConstrainedBox(
          constraints: const BoxConstraints(maxWidth: 520),
          child: const Text('Are you sure you want to delete this team?'),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(dialogContext).pop(false),
            child: const Text('Cancel'),
          ),
          ElevatedButton(
            onPressed: () => Navigator.of(dialogContext).pop(true),
            child: const Text('Delete'),
          ),
        ],
      ),
    );

    if (confirmed != true) return;

    try {
      final delMembersRes = await ref
          .read(supabaseClientProvider)
          .from('team_members')
          .delete()
          .eq('team_id', teamId);
      final delMembersErr = extractSupabaseError(delMembersRes);
      if (delMembersErr != null) throw Exception(delMembersErr);

      final delTeamRes = await ref
          .read(supabaseClientProvider)
          .from('teams')
          .delete()
          .eq('id', teamId);
      final delTeamErr = extractSupabaseError(delTeamRes);
      if (delTeamErr != null) throw Exception(delTeamErr);

      ref.invalidate(teamsProvider);
      ref.invalidate(teamMembersProvider);
    } catch (e) {
      messenger.showSnackBar(
        SnackBar(content: Text('Failed to delete team: $e')),
      );
      return;
    }
  }
}
